因为目前基本上已经解决了于老爷子的和熙熙的问题,所以萧天也是继续去编写代码去了。
毕竟之前那个任务是完成了,但是毕竟人家价格提升上来了,新通讯模块还没有黑人家重新编写一个。
而之前那解决问题的三天时间里面,萧天也是在解决上面这个bug的尝试中,才发觉tcl这种语言先天不足。
因为一旦程序逻辑复杂,它那变量无需声明、变量无类型等等对初学者来说不可多得的“优点”就成了致命缺陷。
这会让人不得不付出比c/c++之类“正规语言”多得多的努力去跟踪去区分数据类型。
而且为了避免错误,萧天也不得不把数据类型也“打包”进数据,然后在程序入口写代码分辨它——尤其是,这些数据类型还是动态的,是从输入数据识别出来的;不结合输入谁都不知道某个数据在某个时刻会是什么。
这使得代码几乎无法静态分析;而测试用例很难覆盖每一条执行路线——不要忘了,这个程序“吃”进去的数据是多变的,几乎不可能列出所有情况。
这使得萧天又产生了一个想法。
那就是,要给它增加一些功能,把专业语言的core dump、变量先声明后使用等等功能搞出来,使得出现类似高危行为时可以得到提醒甚至直接对相关不良行为报错。
当然,萧天没有这么自觉的,只是萧天跟他们说了,他们立刻就又私发了一个六万的悬赏让萧天帮忙!
原本萧天是不愿意的,因为那三天已经够累的了,晚上都熬到凌晨三四点,每天就睡三四个小时,这让萧天深刻的明白为什么程序员容易头秃了。
虽然萧天不愿意,但是奈何对面又把这个六万的金额又加了四万……
嗯,萧天觉得这个功能也不是那么难,熬夜那就熬夜呗……
所以萧天也是立刻就进入状态了,tcl号称一切都是字符串,这甚至可以把系统库函数/运算符/关键字都给rename掉,然后自己写一个替代品。
这给了它的用户极大的自由度。
比如itcl就是用命名空间模拟的面向对象语法——这种语言仍然是面向过程的;但你可以自己定义一个class关键字(实质上是一个过程),把它变得和一个真正的面向对象语言几乎一模一样。
萧天首先盯上的是它的过程/函数声明关键字proc。
在这种语言里,你声明一个函数fun,格式就是
proc fun(arg){
#body
}
它看似一个关键字;但tcl里一切都是字符串,因此这个proc实质上是个函数,它接受函数名、参数列表、函数体三个参数……
萧天也是把系统的proc改名叫_sys_proc,自己写了个proc;这样当用户声明一个函数/过程时,他的声明将以字符串格式先传给他。
这样子的话萧天就可以做一些修改,把一些逻辑插进用户编写的代码中,然后再把修改后的代码传给_sys_proc。
通过这种方式,萧天就接管了tcl的一切;然后修改了它的异常/返回流程,识别出“用户未捕捉的异常”。
毕竟萧天是记录了每个函数在某次被调用时、在调用链上所处的层级。尤其接近顶层尚未捕获就会影响到当前测试用例、当前测试套甚至引起整个程序过早退出,这些都是要记录的。
现在,当程序出错时,如果通过异常处理程序解决了问题、允许程序继续执行了,那么萧天就不做任何动作。
但如果没有处理异常、使得测试失败甚至程序退出,那么萧天就能在执行下一条语句之前把整个调用链打印出来——从函数调用关系到每个函数的局部变量内容、再到异常传递路径,巨细靡遗。
这个设计相当于函数返回时会多执行几条语句,把局部变量等信息保存在内存中;只要程序不崩溃,那么这些信息就自动丢弃;而一旦程序要崩溃,它就会写到磁盘文件中——萧天自己搞了个日志滚动机制,专门记录最近十次崩溃信息,并不会无限侵占磁盘空间。
通过这个东西,再付出微不可察的时间代价,萧天给所有tcl程序增加了core dump功能。
这显然是个重大利好。
这就是为什么他们为什么愿意花费十万请萧天也帮忙做这个功能。
天井市,羽然科技公司。
“老大,我不理解,为什么你要花十万给天天去做这个功能啊?我们自己也可以做啊?”
问话的是一个戴着眼镜,头发稀疏的年轻人。
“小李啊,那这个功能是谁提出来的?”
“是……天天……但是他只是提出来一个概念罢了啊。”
老大叫钱志海,是一个中年人了,他自己开了这个羽然科技公司,员工总共也就只有二三十位,其中程序组就只有四个人,加上他自己兼任总编程,相当于是五个人,他的头发已经稀疏的不成样子了,不过有个假发戴着,还是和一个油光满面的中年人一样。
钱志海看着小李,也就是他的程序组的大将,拥有着中级程序员实力的李明,语重心长的说道,“你不理解来问我,没有错,那你知道为什么老王老杨不来问我?”
“因为他们知道,我们程序员也是有人情世故的,不是说一辈子和计算机打交道,就不需要人情世故,实际上,和计算机打交道的我们,不在本行业的人不需要人情世故那是很正常,但是在本行业里面,不知道人情世故,那是真的很可怕的一件事情,我希望你永远不会明白。”
“就简单的说,你觉得天天技术怎么样?”
李明皱了皱眉头,最后也是叹了口气,“比我强很多,是个大神。”
“是啊,所以你要知道,如果我们向外求一个应用的创意功能,也大概需要花费五六万,那我如果给你们做的话,你们的确是也能够做得出来,但是确定有这个天天本人知道的更清楚吗?而且就技术而言,你们觉得做完这个功能会没有bug吗?”
“如果有bug,那你有把握找的出来吗?”
“我知道你想说有把握,但是我们的这个时间花费在这里,是不是不太值得?”钱志海笑了笑,“而我用十万悬赏交给这个天天去做,不但能做的更好一点,以后要是功能出现bug了,那也不需要我们去找,懂了吗?而且你也是看了这个天天的个人资料吧,最近才开始疯狂接任务,我们将这个给他,也是相当于给了他一个人情,一个大神的人情,你觉得怎么样呢?”
李明这才有点明白过来,老大为什么是老大,那是因为老大已经不仅仅是技术人员,他同时还是一名合格的老板。
…………
另一边的萧天自然是不知道,哪怕知道了,也觉得这是对双方都有利的,不过有一点有些人猜错了,他不是为了钱,而是他熟悉一下能力而已。
不过也不阻碍萧天想着为什么,“可能想让我有售后服务吧……毕竟我在他们眼里就相当于大神一样的人物。”
接下来的几天,萧天就继续的忙碌着他的功能开发了。
这个功能也挺实用的,如果你不想使用,那么不要import debugtools即可——就是把它做到了debug工具库中,你导入这个库,它就立即起作用;你不导入,那就不需要付出任何代价。
因此,这个功能肯定一写出来就会受到欢迎的。
之后的几天,萧天发现了这个功能要比想象中的要好编写。
完成的速度很快,萧天觉得应该是牛人程序员经验知识帮他少走了不少路,所以才能够这么快速大大的缩短了时间。
所以也就在三天后,萧天就已经完成了这个功能的编程,当然也是离不开他的熬夜历程。
所以在提交悬赏之后,萧天终于是松了一口气,他也觉得新能力不错,是时候得筹备自己的公司了。
而另一边,天井市,羽然科技公司。
钱志海就利用这个功能,便通知相关项目组,让他们在自己的项目开头import debugtools。
刚好有个测试任务。
所以没一会儿,他们就排查到了因为这个功能而意外收获的另外一个辅助库的bug。
钱志海等几人大眼瞪小眼。
尤其是李明,用目瞪口呆都不为过,“这个功能怎么像个利器一样啊,我们没有找他,他都额外的给我们发现了辅助库另外的漏洞。”
钱志海也是心中一动,他非常的想把这个天天给拉到他们的公司来,这妥妥的都是大公司精英级别的程序员啊!
他们这个小公司虽然发展的也还行,但是也仅仅是还行罢了,如果能够让天天加入他们,钱志海相信他们的公司绝对能够再创一个新高!
但是……
像天天这样的大神,工资肯定是很高的,就比如那些大公司里面的精英程序员,月入十万都是保底,而且还有奖金分红,而他钱志海能拿出什么来笼络天天大神呢?
不说其他的,就光一个月薪十万,钱志海就拿不出手,也不是说出不起,只是公司还有其他方方面面也要打点,这十万一拿,他们的现金流就更加的不便了。
所以,想要邀请天天大神,钱志海也就只能在心里面想一想,不过他还是看了一眼自己的这几个骨干程序员,“天外有天,人外有人,我们还需要努力啊。不过现在既然发现了这个bug,那就赶紧给它解决吧。”
几个人顿时开始来修复漏洞,首先拿到调用栈信息之后,一会儿时间就很容易的追查到了根源。
钱志海一行人看着这个,都是有些面面相觑。
“怎么是这个……”
这是当年羽然科技公司实现时的疏忽:在某个函数中,他们声明了一个局部变量,这个变量和同一命名空间的另一个变量名字极为相似,但命名风格(首字母是否大写之类)和其他代码不太一致。
当时他们是为了规避不同作用域的命名冲突才这样命名的。
但到了后面,他们仍然习惯性的用了“正常”的命名,也可能是选错了编辑器自动提示选项。
这就相当于丢开局部变量,用了命名空间的外部变量;但从上下文看,这里就不应该碰外部那个同名变量。
用伪码表示大概是这样:
class oneclass {
packagenameitems = null;
....
void funname1(arg){
//initial packagenameitems
packagenameitems = arg;
//other...
}
string funname2(){
packagenameitems = extractpureinfo(packagenameitems);
//do sth
....
result = getitemfrom(packagenameitems, itemname)//1
//do sth
....
return result
}
}
从那里分析,在//1处,本应该是从已经解包过的packagenameitems中,取它的第n项;但这里误传入了解包前的packagenameitems。
似乎输入文本可能会发生几种情况,当然多数情况不需要进一步处理,直接用外部那个变量就行,此时两个变量内容一致,不会触发bug;但少数情况下,外部那个变量需要进一步处理,这才能提取到正确的内容。
这种情况下,两个变量内容不同,误用了前一个变量就读不到正确数据了。
这是个极为隐蔽的逻辑错误。
其实和变量作用域相关的故障都很隐蔽。
李明拿着整个调用链的详细记录,也是看了好几遍才发觉这两个变量的名字似乎有些意思,这才沿着这条线追查下去……
总之,意外的输出信息弄得他们一脸懵逼,因为这时候根本就不应该有这种信息,也幸好检查条件设的比较窄,只有正常返回可通过,其他一概抛异常崩掉——于是这个异常就被叶新晨的debug工具抓到,自动记录了调用栈信息。
所以说为什么之前钱志海等几人会惊讶,因为这个功能给他们抓到了一个bug。
还好这是个极为简单的bug,只需把最后那次访问时,首字符小写的变量名改成大写,故障就不再复发。
其实就这么简单个首字符大小写搞错、误访问了外部变量的bug,羽然科技公司在黑土平台上的悬赏单也是挂了有两三年了,前前后后换了很多人经手,但就是没人能抓到它。
最终,这个简单又奇葩的bug竟然被天天大神的一个功能给抓住了。
不得不说这真的是意外之喜。
“真想见识见识天天这样的大神是什么样的……”
………
毕竟之前那个任务是完成了,但是毕竟人家价格提升上来了,新通讯模块还没有黑人家重新编写一个。
而之前那解决问题的三天时间里面,萧天也是在解决上面这个bug的尝试中,才发觉tcl这种语言先天不足。
因为一旦程序逻辑复杂,它那变量无需声明、变量无类型等等对初学者来说不可多得的“优点”就成了致命缺陷。
这会让人不得不付出比c/c++之类“正规语言”多得多的努力去跟踪去区分数据类型。
而且为了避免错误,萧天也不得不把数据类型也“打包”进数据,然后在程序入口写代码分辨它——尤其是,这些数据类型还是动态的,是从输入数据识别出来的;不结合输入谁都不知道某个数据在某个时刻会是什么。
这使得代码几乎无法静态分析;而测试用例很难覆盖每一条执行路线——不要忘了,这个程序“吃”进去的数据是多变的,几乎不可能列出所有情况。
这使得萧天又产生了一个想法。
那就是,要给它增加一些功能,把专业语言的core dump、变量先声明后使用等等功能搞出来,使得出现类似高危行为时可以得到提醒甚至直接对相关不良行为报错。
当然,萧天没有这么自觉的,只是萧天跟他们说了,他们立刻就又私发了一个六万的悬赏让萧天帮忙!
原本萧天是不愿意的,因为那三天已经够累的了,晚上都熬到凌晨三四点,每天就睡三四个小时,这让萧天深刻的明白为什么程序员容易头秃了。
虽然萧天不愿意,但是奈何对面又把这个六万的金额又加了四万……
嗯,萧天觉得这个功能也不是那么难,熬夜那就熬夜呗……
所以萧天也是立刻就进入状态了,tcl号称一切都是字符串,这甚至可以把系统库函数/运算符/关键字都给rename掉,然后自己写一个替代品。
这给了它的用户极大的自由度。
比如itcl就是用命名空间模拟的面向对象语法——这种语言仍然是面向过程的;但你可以自己定义一个class关键字(实质上是一个过程),把它变得和一个真正的面向对象语言几乎一模一样。
萧天首先盯上的是它的过程/函数声明关键字proc。
在这种语言里,你声明一个函数fun,格式就是
proc fun(arg){
#body
}
它看似一个关键字;但tcl里一切都是字符串,因此这个proc实质上是个函数,它接受函数名、参数列表、函数体三个参数……
萧天也是把系统的proc改名叫_sys_proc,自己写了个proc;这样当用户声明一个函数/过程时,他的声明将以字符串格式先传给他。
这样子的话萧天就可以做一些修改,把一些逻辑插进用户编写的代码中,然后再把修改后的代码传给_sys_proc。
通过这种方式,萧天就接管了tcl的一切;然后修改了它的异常/返回流程,识别出“用户未捕捉的异常”。
毕竟萧天是记录了每个函数在某次被调用时、在调用链上所处的层级。尤其接近顶层尚未捕获就会影响到当前测试用例、当前测试套甚至引起整个程序过早退出,这些都是要记录的。
现在,当程序出错时,如果通过异常处理程序解决了问题、允许程序继续执行了,那么萧天就不做任何动作。
但如果没有处理异常、使得测试失败甚至程序退出,那么萧天就能在执行下一条语句之前把整个调用链打印出来——从函数调用关系到每个函数的局部变量内容、再到异常传递路径,巨细靡遗。
这个设计相当于函数返回时会多执行几条语句,把局部变量等信息保存在内存中;只要程序不崩溃,那么这些信息就自动丢弃;而一旦程序要崩溃,它就会写到磁盘文件中——萧天自己搞了个日志滚动机制,专门记录最近十次崩溃信息,并不会无限侵占磁盘空间。
通过这个东西,再付出微不可察的时间代价,萧天给所有tcl程序增加了core dump功能。
这显然是个重大利好。
这就是为什么他们为什么愿意花费十万请萧天也帮忙做这个功能。
天井市,羽然科技公司。
“老大,我不理解,为什么你要花十万给天天去做这个功能啊?我们自己也可以做啊?”
问话的是一个戴着眼镜,头发稀疏的年轻人。
“小李啊,那这个功能是谁提出来的?”
“是……天天……但是他只是提出来一个概念罢了啊。”
老大叫钱志海,是一个中年人了,他自己开了这个羽然科技公司,员工总共也就只有二三十位,其中程序组就只有四个人,加上他自己兼任总编程,相当于是五个人,他的头发已经稀疏的不成样子了,不过有个假发戴着,还是和一个油光满面的中年人一样。
钱志海看着小李,也就是他的程序组的大将,拥有着中级程序员实力的李明,语重心长的说道,“你不理解来问我,没有错,那你知道为什么老王老杨不来问我?”
“因为他们知道,我们程序员也是有人情世故的,不是说一辈子和计算机打交道,就不需要人情世故,实际上,和计算机打交道的我们,不在本行业的人不需要人情世故那是很正常,但是在本行业里面,不知道人情世故,那是真的很可怕的一件事情,我希望你永远不会明白。”
“就简单的说,你觉得天天技术怎么样?”
李明皱了皱眉头,最后也是叹了口气,“比我强很多,是个大神。”
“是啊,所以你要知道,如果我们向外求一个应用的创意功能,也大概需要花费五六万,那我如果给你们做的话,你们的确是也能够做得出来,但是确定有这个天天本人知道的更清楚吗?而且就技术而言,你们觉得做完这个功能会没有bug吗?”
“如果有bug,那你有把握找的出来吗?”
“我知道你想说有把握,但是我们的这个时间花费在这里,是不是不太值得?”钱志海笑了笑,“而我用十万悬赏交给这个天天去做,不但能做的更好一点,以后要是功能出现bug了,那也不需要我们去找,懂了吗?而且你也是看了这个天天的个人资料吧,最近才开始疯狂接任务,我们将这个给他,也是相当于给了他一个人情,一个大神的人情,你觉得怎么样呢?”
李明这才有点明白过来,老大为什么是老大,那是因为老大已经不仅仅是技术人员,他同时还是一名合格的老板。
…………
另一边的萧天自然是不知道,哪怕知道了,也觉得这是对双方都有利的,不过有一点有些人猜错了,他不是为了钱,而是他熟悉一下能力而已。
不过也不阻碍萧天想着为什么,“可能想让我有售后服务吧……毕竟我在他们眼里就相当于大神一样的人物。”
接下来的几天,萧天就继续的忙碌着他的功能开发了。
这个功能也挺实用的,如果你不想使用,那么不要import debugtools即可——就是把它做到了debug工具库中,你导入这个库,它就立即起作用;你不导入,那就不需要付出任何代价。
因此,这个功能肯定一写出来就会受到欢迎的。
之后的几天,萧天发现了这个功能要比想象中的要好编写。
完成的速度很快,萧天觉得应该是牛人程序员经验知识帮他少走了不少路,所以才能够这么快速大大的缩短了时间。
所以也就在三天后,萧天就已经完成了这个功能的编程,当然也是离不开他的熬夜历程。
所以在提交悬赏之后,萧天终于是松了一口气,他也觉得新能力不错,是时候得筹备自己的公司了。
而另一边,天井市,羽然科技公司。
钱志海就利用这个功能,便通知相关项目组,让他们在自己的项目开头import debugtools。
刚好有个测试任务。
所以没一会儿,他们就排查到了因为这个功能而意外收获的另外一个辅助库的bug。
钱志海等几人大眼瞪小眼。
尤其是李明,用目瞪口呆都不为过,“这个功能怎么像个利器一样啊,我们没有找他,他都额外的给我们发现了辅助库另外的漏洞。”
钱志海也是心中一动,他非常的想把这个天天给拉到他们的公司来,这妥妥的都是大公司精英级别的程序员啊!
他们这个小公司虽然发展的也还行,但是也仅仅是还行罢了,如果能够让天天加入他们,钱志海相信他们的公司绝对能够再创一个新高!
但是……
像天天这样的大神,工资肯定是很高的,就比如那些大公司里面的精英程序员,月入十万都是保底,而且还有奖金分红,而他钱志海能拿出什么来笼络天天大神呢?
不说其他的,就光一个月薪十万,钱志海就拿不出手,也不是说出不起,只是公司还有其他方方面面也要打点,这十万一拿,他们的现金流就更加的不便了。
所以,想要邀请天天大神,钱志海也就只能在心里面想一想,不过他还是看了一眼自己的这几个骨干程序员,“天外有天,人外有人,我们还需要努力啊。不过现在既然发现了这个bug,那就赶紧给它解决吧。”
几个人顿时开始来修复漏洞,首先拿到调用栈信息之后,一会儿时间就很容易的追查到了根源。
钱志海一行人看着这个,都是有些面面相觑。
“怎么是这个……”
这是当年羽然科技公司实现时的疏忽:在某个函数中,他们声明了一个局部变量,这个变量和同一命名空间的另一个变量名字极为相似,但命名风格(首字母是否大写之类)和其他代码不太一致。
当时他们是为了规避不同作用域的命名冲突才这样命名的。
但到了后面,他们仍然习惯性的用了“正常”的命名,也可能是选错了编辑器自动提示选项。
这就相当于丢开局部变量,用了命名空间的外部变量;但从上下文看,这里就不应该碰外部那个同名变量。
用伪码表示大概是这样:
class oneclass {
packagenameitems = null;
....
void funname1(arg){
//initial packagenameitems
packagenameitems = arg;
//other...
}
string funname2(){
packagenameitems = extractpureinfo(packagenameitems);
//do sth
....
result = getitemfrom(packagenameitems, itemname)//1
//do sth
....
return result
}
}
从那里分析,在//1处,本应该是从已经解包过的packagenameitems中,取它的第n项;但这里误传入了解包前的packagenameitems。
似乎输入文本可能会发生几种情况,当然多数情况不需要进一步处理,直接用外部那个变量就行,此时两个变量内容一致,不会触发bug;但少数情况下,外部那个变量需要进一步处理,这才能提取到正确的内容。
这种情况下,两个变量内容不同,误用了前一个变量就读不到正确数据了。
这是个极为隐蔽的逻辑错误。
其实和变量作用域相关的故障都很隐蔽。
李明拿着整个调用链的详细记录,也是看了好几遍才发觉这两个变量的名字似乎有些意思,这才沿着这条线追查下去……
总之,意外的输出信息弄得他们一脸懵逼,因为这时候根本就不应该有这种信息,也幸好检查条件设的比较窄,只有正常返回可通过,其他一概抛异常崩掉——于是这个异常就被叶新晨的debug工具抓到,自动记录了调用栈信息。
所以说为什么之前钱志海等几人会惊讶,因为这个功能给他们抓到了一个bug。
还好这是个极为简单的bug,只需把最后那次访问时,首字符小写的变量名改成大写,故障就不再复发。
其实就这么简单个首字符大小写搞错、误访问了外部变量的bug,羽然科技公司在黑土平台上的悬赏单也是挂了有两三年了,前前后后换了很多人经手,但就是没人能抓到它。
最终,这个简单又奇葩的bug竟然被天天大神的一个功能给抓住了。
不得不说这真的是意外之喜。
“真想见识见识天天这样的大神是什么样的……”
………