从游--工作啊!
[00:34.910]覚えてますか 教室の [00:34.910]你还记得吗 教室里 [00:40.870]一番後ろ さびしげな場所 [00:40.870]最后方的角落 充满寂寞的地方 [00:47.000]いつからだろう 私はいました [00:47.000]不知从何时起 我就身处此地 [00:52.870]誰にも見えず 1人で [00:52.870]不被任何人所注意 独自一人 [00:58.460]覚えています 教室の [00:58.460]我还能记起 教室里 [01:04.250]窓際の席 退屈そうに [01:04.250]你坐在靠窗的座位上 显得很无聊 [01:10.400]後ろを向いた あなたはなぜか [01:10.400]回头望来的你不知为何 [01:16.180]不思議そうな顔で 笑った [01:16.180]带着意外的表情 对我笑了 [01:24.280]桜舞い落ちる 坂道を駆け下りていく [01:24.280]樱花飞舞飘落 我飞奔下坡道 [01:31.060]私の足音に あなたが気付いたら [01:31.060]我那声声足音 若是你能注意到 [01:37.040]あのね ずっと忘れない [01:37.040]那个啊 我永远不会忘记 [01:42.840]はじめて恋をしたあの季節 [01:42.840]初次感受恋心的那个季节 [01:46.990]そっとかいだ桜の匂い [01:46.990]我所嗅到的 那樱花的味道 [02:02.790]春夏秋冬 教室で [02:02.790]一起走过春夏秋冬的教室里 [02:08.510]あなたの日々を眺め続けた [02:08.510]遥望着你度过着每一天 [02:14.780]時々そっと あなたが振り向く [02:14.780]时不时你也会悄悄回过头来 [02:20.630]私もそっと手を振って 笑った [02:20.630]我也会轻轻向你挥挥手 露出笑容 [02:28.810]桜舞い落ちる 校門をくぐっていった [02:28.810]樱花飞舞飘落 我穿过校门 [02:35.450]遠ざかるあなたの 背中に呼びかけた [02:35.450]向着远去的你的背影 大声呼喊 [02:41.430]あのね ずっと ありがとう [02:41.430]那个啊 一直以来谢谢你 [02:47.140]涙にかすむ思い出に [02:47.140]给予我这被泪水模糊的回忆 [04:10.500]卒業おめでとう [04:10.500]恭喜毕业 [04:12.560]あなたへと届けたい歌 [04:12.560]这首想要传达给你的歌 [04:16.890]舞い散る花ビラに たくして未来へと [04:16.890]寄托于纷飞的花瓣之上 飞向未来 [04:22.960]あのね いつか めぐりあう [04:22.960]那个啊 终有一日我们能够重逢 [04:28.850]新しい季節を信じ 私も行くね [04:28.850]我相信崭新的季节即将来临 而我也将启程 [04:35.770]GHOSTxGRADUATION [04:35.770]GHOSTxGRADUATION [04:39.870]ひらり 桜のように [04:39.870]飘扬着 像樱花那样
因为工作繁忙,虽然许久不见,但我终于从学校毕业,成为社会的一员了。[似乎有不少巨坑,但没关系,慢慢填,总会填完的。]
搬出许久之前的一张图

计算机能成为单独的一个分支,必然是有它的理由的,可以很复杂,也可以很简单。我就从最近公司遇到的一个实际场景说起吧,事情的起因是下面的一张图

我目前所做的事是“自动化设备的上位机软件开发”,属于类似进厂的生产制造业,而且在生产工艺上,我们属于长流程的一类,做出一个产品要较长的时间,而且一旦中间某个环节出现问题,就只能重头再来。因此软件闪退确实是一个大问题,“找出原因,并解决”是当前的头号任务。
闪退无处不在,一般人遇到也只能像无头苍蝇一样,尝试打补丁、提权限、清后台、升系统等各种各样的方式,有时确实能成,但失败的概率往往是很大的,因为这都是毫无根据的,我很喜欢一个UP主的话“计算机不会说谎,一定是哪里不对劲”。数学和计算机可是两个出了名的纯粹严谨之神,一切错误是必然存在原因的。
接下来我来简单讲一下我的分析过程吧,虽然讲述的过程是顺利的,但实践查找的过程还是挺困难的。当一个程序奔溃闪退的时候,我们可以使用各种办法来给程序生成一个转储dump文件,其用于给闪退一个快照,以方便我们的后续分析。巧合的时,我们的程序可以直接生成,所有省心了很多。
对于dump的分析,使用windows自带的windbg即可,一看错误原因“Unknown exception”,吓得我马上看了一下调用栈堆

问题出现在my_cross_platform.dll
的库上,而最后的死亡节点是kernelbase直接RaiseException抛出异常,看来问题并不简单。我承认我确实不是很懂windows的异常机制,所以我们直接查看my_cross_platform(基地址0x51240000)最后的偏移(0x1f3ec)位置

原来异常是程序自己抛出来的,40000015的异常码也是从这里出来的……哦,原来如此……不对吧,异常捕获和处理呢?总不能抛出异常后就什么都不管了吧……嗯,window系统级异常,捕获处理只会有更多问题,嗯,原来如此……这个my_cross_platform是哪里跑出来的玩意。
仔细一看,是我们上位机使用的工业视觉处理软件VisionMaster3.4提供的SDK,这好办,直接找供应商就行了……真的吗?……“版本太旧,不再维护,请升级最新版。”,也就是要升级4.3吧,说得容易,也不看看SDK的API变化到底有多大。算了,自己再分析吧。
按照供应商的说辞,他们的库使用了第三方库,第三方库的错误不好排查,最新版将其替换了,所以升级后会变得更加稳定,具体是什么,他们也没细说。但为他们收集日志的过程中发现,原来视觉软件下也有一系列的dump文件,其包括主程序VisionMaster、后台服务VisionMasterServer、加密狗代理VmModuleProxy。调查它们的调用栈堆后发现,所有的崩溃全都是因为程序主动调用了RaiseException,但有特例,除了Server的奔溃来自libzmq外,其它都同样来自my_cross_platform。
看到“libzmq”,我的DNA沸腾了起来,怎么看都是一个开源库吧,一个通信开源库,终于可以不用去看烦人的汇编了,dll还好心地把版本4.3.2给标上了。直接上源代码,查找RaiseException,其位于zmq::zmq_abort中,而这个函数会被调用在zmq中基本是因为各种assert失败导致的,无聊之下看了看my_cross_platform的前几层栈堆

一眼鉴定,海康说的所谓的第三方库就是ibzmq不会跑了,那出错的地方应该也同样是这里了。在libzmq中,断言错误信息会输出到stderr中,这没办法看到,那就只能拿出我们的动态调试工具x64dbg来设置断点拦截,然后直接从内存中看出来了。由于这玩意只能在厂房挂较长时间才能看到,我就直接说结论吧,我们看到了wsa给出的“Connection reset by peer”……好吧……由于没有外部连接,全是程序内部使用环回链路进行通信,所以我们直接把整个互相通信的程序全部动态调试并下断点,于是我们找到了最初的断言失败点,是zmq::signaler_t::send的“zmq_assert(nbytes==sizeof(dump))”断言失败。
也就是本应该发送一个字节数据,却没发送一个字节数据,从而导致断言失败,从而导致整个程序退出……我……我好像还没有缓过来……虽然我并不熟悉网络通信过程,但我知道网络通信一直都是充满意外的,针对各种可能出现的意外,进行相应的异常处理,本来就是通信者应该做到的事情……但是……它竟然……只是因为一个数据发送的失败……就直接抛出异常……让程序直接终止。
冷静下来看了看issues,发现原来大家都遇到过同样的问题,我们并不是个例。算了……查出问题的最后,还是要解决问题……版本升级竟然没有用……而这是作者的原话“The implementation is quite simple in this regard: on Windows there’s a TCP socket bound on INADDR_LOOPBACK and random port (0). If something on the system messes with that loopback connections, things go awry.”总结一下就是要我们去排除那个“something messes with loopback connections”,程序并不对这些mess进行处理。
别说排除mess了,光找到它都是几乎不可能的,调试window内核,我可没那么高的等级,而且我真的太不想跟windows打交道了。最后再怎么跟供应商扯皮也是没有用的,他们把矛盾转移到第三方库上,并继续拿出一张PPT截图

说“升级”才是目前最好的解决方法……为了解决问题,只能升级了呗……没办法,谁让这就是工作呢!
终于讲完了呢!这段痛苦的经历实在是不想回顾了,实际上为了临时解决闪退的问题,对zmq进行了各种拦截,但最后只会引发连锁反应,发生更多的异常闪退,只能说zmq一旦在主进程的内存空间中就会有无尽的潜在危险。这件事确实引发了我的很多思考。
会写程序的人很多,但真正精通计算机的确实不多,什么叫精通计算机呢?简单来说就是我之前所说的非常了解计算机运行机制的程序大佬,在计算机中,我非常羡慕的一直是那么几类人,搞程序逆向的、搞网络攻防的、研究系统漏洞的等等,甚至还有硬件漏洞,比较著名的就是Spectre和Meltdown,而想要搞透这些,写程序只是基本功。就算是单纯的程序员,强大的debug能力,也是令人羡慕的,但一切的前提都是了解计算机底层运行机制……偷偷说一句,经过这次事我才知道,闪退原来可以分析dump文件。
另一方面就是商业的技术支持可能并没有想象中的那么好,能用更快更简单的方法,比如升级,他们就会选择,而不会想适应情景的方案。至于我们为什么不升级……大概大家都是同样的想法吧……一个字“懒”。同时我们也看到了开源库存在的潜在风险,但我依旧是开源的支持者,因为开源至少能减少很多时间的浪费。
……升级真的可以解决所有问题吗?答案是

我们的程序并没有使用.net框架,但会弹出clr exception,那么问题一定出现在VisionMaster4.3提供的基于COM组件的ActiveX控件了,其注册使用的是regasm……懂了吧。而最终真正合适的解决办法是,把VisionMaster隔离成一个单独的程序,这样闪退至少不会影响到主程序。结果绕了一大圈,回到了最为朴素的方法,真是讽刺呢……
数学的选择:虽然嘴上说着放弃数学,但真要放弃数学是不可能的,目前主攻的科目是代数几何,方向为IUT和BSD,因为我深爱着错综复杂的逻辑链条与联系。
程序的选择:程序方面主要走软硬件结合,特别是电气相关的应用物理,也就是我现在正在做的事情,理论物理就扔给数学吧,平常则是专研运行机制和漏洞方面。
游戏的选择:复杂的东西真不想搞,也没精力搞,只走一个人也能完成的路线,其中的Galgame是最好的选择。
如此看来,至始至终我就从没有改变过。