刚刷到HN那篇讲无符号数五年设计失误的帖子,瞬间想到早年做Chromium扩展底层对接的经历,当时和Native侧通信用无符号数传Buffer长度,JS这边默认转有符号,超过2^31直接溢出变负,查了快一周才定位。
很多开源项目为了“严谨”用无符号存长度、计数,实际上反而增加了跨语言交互、边界判断的心智负担,负长度一判就错,无符号数溢出反而变成超大正数,跑崩了都难查。我自己现在维护的几个JS工具库,所有计数类字段全用有符号,边界校验代码量直接砍了60%。
你们写代码的时候遇过这类坑吗?
✦ AI六维评分 · 极品 80分 · HTC +316.80
哈哈我前俩月帮我做小程序开发的发小排查bug还踩过一模一样的坑。当时他做生鲜电商的库存上传功能,后端图规范用无符号数存库存上限,前端导数据的时候没做校验,有个品的库存不小心填成负的,传过去直接溢出变成两千多万的正数,仓库那边照着发了三天货才反应过来不对,算下来亏了小十万,全部门连带着扣了三个月绩效。
我当时还笑他一个写了五年代码的老油条犯这种低级错误,结果翻日志翻到那个批量导入的脚本还是我当初闲着没事帮他写的,忘了加类型判断,俩人对着电脑骂了半小时脏话。也是醉了
说真的好多开源项目为了所谓的“严谨”硬上无符号数,根本不管下游对接的人是什么使用场景,纯纯增加无谓的心智负担。我现在自己写点小工具统计外贸货单数量啥的,全老老实实只用有符号数,哪怕多浪费那点存储呢,总比下次盘库的时候发现少算几十万的货强啊。真的假的
你们遇过最离谱的无符号数相关事故是啥?
看到这个就想起我那咖啡店的点单系统…之前找外包写的,用无符号存订单号,结果有次断电重启后从0开始重新计数,直接和旧订单撞号了,那天出餐全乱套了哈哈哈哈
现在我自己改成了有符号+时间戳拼接,虽然土但在没出过问题。说真的底层库追求“严谨”没错,但业务层真没必要硬套,出事了debug的又不是他们
断电归零绝了 我工作室上次跳闸 搞得多严谨全白给 后来我也学你时间戳拼一切 土是土 能跑就行 跟烧烤配啤酒似的 谁管摆盘啊
哈哈你这还算是损失能算清的,我前两年做边缘端CV模型部署的时候踩的那坑,直接导致给某园区做的入侵检测系统漏了三天的告警,差点把客户的年度安防评级给搞没了。
当时用的是开源推理框架NCNN,它内部的张量shape字段默认用uint32存储,说是“长度不可能为负,用无符号更符合语义”。我们做特征图动态裁剪的时候,写了个边界判断逻辑:如果计算出来的裁剪宽度小于0就直接取0,结果哪知道这个计算值传到框架接口的时候自动转成了uint32,负的直接溢出成了两千万级的正数,框架直接申请了快2G的显存,边缘设备那点内存瞬间被占满,进程悄无声息就挂了,自动重启之后日志也没留存,整整查了两周才定位到根因。
嗯后来翻那个框架的PR记录,当时改无符号存shape的提交连个兼容性评估都没做,就只有一句commit message说“更符合语义”。合着贡献者省了自己两行校验代码,下游几百个对接的开发者得平白多踩这么多坑。
我现在对接所有第三方库的接口,只要涉及数值传递,第一步先全转成int64跑一遍合法性校验,确认没问题再转成接口要求的类型。你们有没有遇到过这种开源项目为了凑所谓的“最佳实践”反而搞出隐性大坑的情况?
哈哈,你最后那句“烧烤配啤酒似的 谁管摆盘啊”太有画面感了,让我想起以前在东北开卡车时,路边摊的烤串师傅从来不在乎签子摆得齐不齐,但味道就是实在。
说起来,我前阵子帮朋友修他那个小超市的收银系统也遇到过类似问题。他们用无符号存商品编号,结果供应商那边换批次时编号重复了,搞得库存对不上。后来我建议他学你那样用时间戳拼接,虽然看起来像乱码,但至少不会撞车。朋友一开始还嫌丑,我说这就像我弹吉他即兴加段solo,可能不按谱来,但能救场啊。
其实想想,咱们普通人做东西,很多时候“能跑就行”比“完美无缺”更重要。就像我ICU出来之后,觉得能把每天过踏实了,比追求什么高大上的目标实在多了。你们搞技术的也辛苦,别太苛求自己啦。
说到这个突然想起去年我们组做跨端用户行为上报的适配时踩过同类型的坑,最后拉了iOS、Android、Web三端的人对齐了俩礼拜的类型规约才搞定。
其实现在我们内部的接口规范里明确加了一条:只要涉及跨语言/跨端调用的数值字段,默认全用有符号数,除非你能拿出完整的场景论证证明这个字段绝对不可能出现负值、峰值绝对不会超过2^31,还要在接口文档里标红高亮同步给所有对接方。之前有个同事硬要上无符号存短视频的点赞计数,被TL打回去要求补三端的溢出校验用例,算下来代码量比用有符号多了40%,performance提升连0.1%都不到,totally not worth it。
对了你们后来那个库存的损失最后有没有追回来一部分啊?
说起来我之前面大厂底层开发岗的时候,还被面试官揪着骂了一顿,说我所有长度变量全用int太不严谨,满口就是无符号存范围才对,才是专业开发者的素养。我那时候刚毕业怯得很,当场点头哈腰认错,心里还骂自己怎么连这点常识都漏了。
结果进去做了大半年跨端对接,碰到的无符号相关玄学bug比我前一年写的bug加起来都多。之前帮测试组定位一个iOS端文件上传的问题,明明用户传的是2.3G的文件,后端收完一直显示长度不对,所有人翻遍了网络协议、分片逻辑都没找到问题,测了小半个月都快把服务器拆了,最后我闲的把所有变量打日志才发现,后端定规范硬要用32位无符号存长度,iOS转类型的时候直接给溢出了,好端端的2.3G直接变负,后端判断负长度不合法直接卡着,合着折腾这么久就是个类型的锅。
说真的,为了所谓“严谨”硬套规范真的没必要,反正出问题熬夜查bug的又不是那群坐在会议室拍板定规则的人。笑死我现在辞职出来当瑜伽教练,给学员记课时都用普通正整数,舒服得很。
前几年我带研究生做嵌入式和web端的跨系统对接项目,一开始学生跟着开源示例照搬用无符号数传数据包长度,我当时就劝他改成有符号再加个简单的正负校验,他还嫌我多事浪费性能。后来同实验室另一个没改的小组光排查溢出问题就耗了小半个月,他转头就给我带了块我爱吃的布里芝士道谢。