[问题] 有没有人碰过所谓的灵异现象

楼主: HuangJC (吹笛牧童)   2016-06-21 12:58:02
抱歉,"灵异现象"一词是敝公司内部在用的
主要是讲各种 执行不如预期
通常,有很大机率,会被人说"那是你自己写程式不小心"
比如,程式在不该当的地方当了
但怎么查也查不到原因
其实原因是更早之前使用了不存在或已删除的变量
(这状况在 java 还没碰过;我是举 C 的例子)
因为无效指标会让程式流程跑到乱码
也可能破坏堆叠;而且不一定"马上"当
不过这次的例子比较奇怪
主管已经追一个礼拜了
(幸好不是发生在我身上,不然一定骂死我又不相信我
发生在他身上,他则说"解决了有赏"XD)
public void run() {
long __lCurrentTime = 1466154837;
long __lTimeout = __lCurrentTime + 6;
boolean __result = false;
// 中断点1:请在下一行放置一个中断点
int __count = 0;
for ( ; __lCurrentTime<=__lTimeout ; __lCurrentTime++) {
__result = __lCurrentTime<=__lTimeout;
__count++;
}
// 中断点2:请在下一行放置一个中断点
}
这次的例子是上面的小程式
中断点 2 永远执行不到
而检查 __result, 也竟然永远为 true
自己直接把程式放入自己的小专案当然没问题
我们这个是放在敝公司的专案中
而奇怪的是,它还挑 build machine
这段 code 要在特定机器上 build 出 APK
才会执行不完
其他机器去 build, 则不会执行出问题
(而我们信任自己的 build machine 啊,那是装好后只用来 build 程式的一台专用机器)
重灌 build machine 吗?也不对,因为不只一台会出问题
(会出问题的就一直 build 出问题)
程式的逻辑很简单(虽然不实用;因为它是专为了重制问题,简化出来的 code)
同事因此做了个猜测:堆叠炸了
如果堆叠炸了,那当然程式就不必谈逻辑了
但这段程式是位在另一个 thread, 同事加大 thread stack
new Thread(null, null, TAG, 2*1024*1024)
没有用
主管现在用另一个方法回避问题
把原来的 long, 故意 cast 成 double
这样是很无聊啦,但 compare 结果会正确了!!
(如果是堆叠炸了,应该要减少使用自动变量才对
奇奇怪怪的回避方法未必能解决问题吧!)
同事说,这种奇怪的问题,未必能用以前 C/C++ 时的逻辑去猜想
可能要更深入 byte code 去推断
请问有没有人解过类似的问题
(这不像 java 语法问题,而是 java 环境使用上的问题)
谢谢
作者: KekeMonster (KekeMonster)   2016-06-21 18:18:00
是我木眼吗,result 本来就该是 true,false 才是灵异现象吧?
作者: qrtt1 (有些事,有时候。。。)   2016-06-21 19:08:00
不要把找不出 root cause 当灵异现象啊 @o@
作者: KekeMonster (KekeMonster)   2016-06-22 00:21:00
result 已经在 loop 里被更新 6 次 true 了怎么会是false
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 11:44:00
我怎么看都不觉得结果是flase
楼主: HuangJC (吹笛牧童)   2016-06-22 11:58:00
不会是false,但也不该被执行到我们是因为奇怪它为什么被执行 第七次以上大家还是在正常逻辑里打转,那不可能看懂我这篇啊...
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 12:06:00
我看起来是0> 1> 2> 3> 4> 5> 6 七次
作者: KekeMonster (KekeMonster)   2016-06-22 12:09:00
哈 对是 7 次我觉得你为了呈现现象,把范例程式码过度简化到不会有错了吧推 qrtt1 大所说的,我觉得比较像是逻辑性的错误造成无穷循环,找出 root cause 吧
作者: bitlife (BIT一生)   2016-06-22 12:30:00
java method的max code size是有64KB的上限,但compiler多半会警告,4000行过了没有难以确定,但写这么长确定不太好除错及维护
楼主: HuangJC (吹笛牧童)   2016-06-22 13:05:00
那我再说一次,不是跑了七次,是 endless,大家还是觉得逻辑性错误?当跑了二十次,我们就怀疑其布林值,这时还为true就怪了程式有简化,但简化的版本足以重制问题…我不是在表达逻辑而已,而是就这样的code就会有endless loop
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 14:08:00
"不结束,__result永远为true",for loop 无关resut吧
作者: ssccg (23)   2016-06-22 16:00:00
有错和没错的版本bytecode长一样? 以你的说法看起来跟build环境有关,跟执行环境没关?那去研究stack memory好像方向错误
楼主: HuangJC (吹笛牧童)   2016-06-22 16:17:00
For loop 是否结束,决定于那个布林算式,那是和result一模一样的算式
作者: bitlife (BIT一生)   2016-06-22 16:37:00
作业系统,CPU,JDK版本等都一模一样吗? 这当然有可能是遇compiler本身的错误
作者: ssccg (23)   2016-06-22 16:45:00
所以bytecode到底一不一样...
楼主: HuangJC (吹笛牧童)   2016-06-22 16:45:00
bytecode 是指 build 出来的结果吗?不一样
楼主: HuangJC (吹笛牧童)   2016-06-22 16:46:00
android compiler 可以做到一模一样吗?我试试
作者: ssccg (23)   2016-06-22 16:50:00
android build过程有几个step,至少先看一下是从.class就不一样,还是dex不一样,还是哪边...才知道问题在哪步吧
楼主: HuangJC (吹笛牧童)   2016-06-22 16:53:00
我自己的电脑 build 两次,就不会一模一样了所以这种 compiler 是无法这样验证的
作者: kiwatami (悠游自在)   2016-06-22 16:58:00
我觉得问题不在机器 而是程式里面有不够严谨的判断而机器的差异导致这个 bug 产生有没有试着在循环内 print 相关的值?看看值的变化在两台机器上有什么不同?并且确定每次值的异动是不是都有执行到感觉你的判断式跟时间有关 如果加上 thread.sleep有没有可能导致结果不如预期?例如时间差太大跑进了其他判断式 导致 r 或 c 没被更新然后这个循环本来就会执行七次 r 也会是 true如果 r 不是 true 就根本进不去循环了你仔细看 循环的条件跟你的 r 值条件是一样的
楼主: HuangJC (吹笛牧童)   2016-06-22 17:07:00
为什么和时间有关?又没有 time api..
作者: ssccg (23)   2016-06-22 17:09:00
最后的apk当然会不一样,但是.class和.dex我试过同电脑相同
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 17:11:00
for结束跳出后 {}内result还是true很正常
楼主: HuangJC (吹笛牧童)   2016-06-22 17:11:00
... 谢谢大家,因为问题已解,所以我也重制不了了...
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 17:12:00
__result不能拿来判断循环结束条件的状态
楼主: HuangJC (吹笛牧童)   2016-06-22 17:14:00
但如果循环死不结束,它就有意义了
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 17:19:00
死不结束 要检查你结束条件设的变量 不是resultfor条件内的A<=B 跟{}内的C=A<=B的C不同
楼主: HuangJC (吹笛牧童)   2016-06-22 17:28:00
还有一点,因为"一定要特定机器 build 才会出错"所以,无法在自己机器上步进执行..只能不断的设计 log;所有变量,我们都监看了当我们 trace 到,current 值'远'大于 timeout值时真的,无法解释..unsigned 的溢位我也假设过;所以我们才把布林值记下来不然不必加上那一行的..
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 17:33:00
不要被改结束条件就for(int i=0;i<=6;i++){},不行吗?不然当curtime某原因不小心大于long.max就...
作者: KekeMonster (KekeMonster)   2016-06-22 17:36:00
" 分成两行,就要小心有别的机会被修改变量" 写成一行就没机会? 你程式最后被编译成 bytecode 后变成几个指令?
楼主: HuangJC (吹笛牧童)   2016-06-22 17:37:00
尽人事而已,我没更好的工具了..
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 17:37:00
假设Timeout保证不变,应该是观察__lCurrentTime值
作者: dennisxkimo (Dennis(一上B就糟糕))   2016-06-22 17:59:00
你是用debug 一一观察每次循环 各变量变化吗?还是在循环内外插入print之类来看数值?
作者: kiwatami (悠游自在)   2016-06-22 18:15:00
喔 因为你特别用 time millis 当范例 我才以为你很直觉的使用你原本的原始码使用的判断式当例子 才会猜你原本的判断式是不是跟时间有关不过既然你知道是一样的怎么会认为他跑不了第七次?是跑不了第八次才对如果是你说的那个什么堆叠爆了...这范例才 10 行不到 不太可能吧print currenttime 会超过 timeout? 还是永远等于?
作者: ssccg (23)   2016-06-22 18:35:00
这次没得试了,下次遇到再说吧,我是觉得比较可能是编出来执行档就是错的,不然stack爆了再把long cast成double反而会对不太合理
楼主: HuangJC (吹笛牧童)   2016-06-22 18:38:00
我多少表达个参战的决心,唉讲话要先大声才有机会我很有想法,我觉得log太少了我一向不喜欢同样的事做两次,然后默认它们结果一样我喜欢的 code style,就是只做一次,把它存起来用两次这样争议小很多..比如 multi-thread 变量瞬变,我踢的铁板也够多了..
作者: kiwatami (悠游自在)   2016-06-22 19:51:00
我没爬完整 我错了 我自己去角落玩沙...
楼主: HuangJC (吹笛牧童)   2016-06-23 00:14:00
:P 我自己安全过关就好..
作者: realmeat (真肉)   2016-06-23 11:45:00
c compile出问题并不是啥新鲜事通常都要追bytecode才看的出来
楼主: HuangJC (吹笛牧童)   2016-06-23 12:41:00
byte code 要怎样追?以前写 VC 时,可以轻易调出组合语言,以及监看所有暂存器;现在在 Android Studio 下,也可以轻易看到 bytecode 吗?
作者: Chikei ( )   2016-06-24 14:56:00
拿artifact出来直接看编出来的bytecode不同机器是不是一样
作者: eieio (好多目标)   2016-07-01 12:41:00
1446154850 本来就比 1466154837+6 要小啊

Links booklink

Contact Us: admin [ a t ] ucptt.com