【BUG分析】tabs页面嵌套tab关闭时会报错的分析【期待一鹤看到后修复下】

小肥羊 19小时前 57

现象:这个错误的触发是在关闭时触发的,消息循环退出,正常来讲对软件体验没有任何影响,因为感知不到,几乎不存在

发现经过:自己在公司写了几个小工具,几个同事在用,做了个网络收集错误信息的功能,每次触发错误都会提交到服务器,然后就发现数据库存在同一个错误,并且是每次关闭软件几乎都会触发,因为不影响使用,所以一直没管,最近在处理数据时发现这些错误太影响数据筛选了,就着手分析了一下。

先说结论:问题不是很复杂,但是不太容易发现

tab.aardio 中在组件销毁时会发送【removeAll函数中】,下面是代码,是通过for循环进行删除的

 removeAll = function(){    	   
			for(i=#owner._forms;1;-1){				
				::SendMessage(owner._forms[i][["hwnd"]],0x10/*_WM_CLOSE*/);
				..table.remove(owner._forms,i );
			}  
			owner.form = null; 
			..table.pop(owner._history,#owner._history)
    		::SendMessage(owner.hwnd ,4873 )   
    	}

但是如何tab窗口在激活,在前台时,在win.ui._aardio中,【第979行】,也会有一个销毁窗口的循环,

for(k,f in _forms){
	::SendMessage(f.hwnd,0x2/*_WM_DESTROY*/); 
}

消息在退出循环时,如何ui的删除恰好在rab的removeAll进入循环后,就可能导致tab中for循环的句柄被提前销毁,就会导致tab中的removeAll报错。

改进方法:在removeAll函数的for循环内SendMessage前做一次句柄是否为空的判断即可



附件是一个演示工程,内容很简单,都是空的。

1、首先贴一下报错信息

 {File}:E:\Aardio_IDE\lib\win\ui\ctrl\tab.aardio
{Line}:#163
{Error}:
{Calling}:'SendMessage'
{Bad argument}:@1
'
{Expected}:number
{Got}:null'

调用栈
	[kernel]: in function 'SendMessage'
	E:\Aardio_IDE\lib\win\ui\ctrl\tab.aardio:163: in function 'removeAll'
	E:\Aardio_IDE\lib\win\ui\ctrl\tab.aardio:205: in function '_onDestroy'
	E:\Aardio_IDE\lib\win\ui\_.aardio:898: in function 'proc'
	E:\Aardio_IDE\lib\win\ui\_.aardio:305: in function <E:\Aardio_IDE\lib\win\ui\_.aardio:297>
	[kernel]: in function 'SendMessage'
	E:\Aardio_IDE\lib\win\ui\_.aardio:979: in function 'proc'
	E:\Aardio_IDE\lib\win\ui\_.aardio:305: in function <E:\Aardio_IDE\lib\win\ui\_.aardio:297>
	[kernel]: in function '_defWindowProc'
	...
	..._IDE\lib\win\ui\ctrl\metaProperty\_.aardio:236: in function 'close'
	...\Aardio_IDE\lib\win\ui\simpleWindow.aardio:25: in function 'oncommand'
	E:\Aardio_IDE\lib\win\ui\tracker.aardio:87: in function <E:\Aardio_IDE\lib\win\ui\tracker.aardio:67>
	[kernel]: in function 'call'
	..._IDE\lib\win\ui\ctrl\metaProperty\_.aardio:304: in function 'wndproc__'
	..._IDE\lib\win\ui\ctrl\metaProperty\_.aardio:339: in function <..._IDE\lib\win\ui\ctrl\metaProperty\_.aardio:336>
	[kernel]: in function 'messageTranslateDispatch'
	E:\Aardio_IDE\lib\win\_.aardio:557: in function 'parseMessage'
	E:\Aardio_IDE\lib\win\_.aardio:593: in function <E:\Aardio_IDE\lib\win\_.aardio:581>
	(tail call): ?

2、可以看到是tab文件的163行报错

 removeAll = function(){
	for(i=#owner._forms;1;-1){
/*这一行*/	
		..table.remove(owner._forms,i );
	}  
	owner.form = null; 
	..table.pop(owner._history,#owner._history)
    	::SendMessage(owner.hwnd ,4873 )   
    	}

错误信息看出是参数1句柄为空。

3、我们修改库文件,输出owner._forms到文件中看看,这里不能用console打印,因为是在关闭时触发

removeAll = function(){
    	   
			for(i=#owner._forms;1;-1){
				::SendMessage(owner._forms[i][["hwnd"]],0x10/*_WM_CLOSE*/);
				..table.remove(owner._forms,i );
			}  
			owner.form = null; 
			..table.pop(owner._history,#owner._history)
    		::SendMessage(owner.hwnd ,4873 )   
    	}

结果显示数据如下:

{
[1]={hwnd = 658878;};
[2]={hwnd = 396666;};
[3]={hwnd = 1183420;}
}

也就意味着在函数进入时

owner._forms[i][["hwnd"]]

是不会出现空值的,也说明在循环过程中,某一个环节,传入进去的hwnd为空了。

于是我们进一步打印信息:

多次运行触发错误,取其中一次数据如下:

发现循环在循环第二次时,owner._forms整个表都为空了。

继续寻找,发现win.ui._aardio也在销毁同一个句柄,其代码如下,我们也做一下信息打印


打印信息如下:


图中,首先在tab的循环外有2个句柄待关闭,注意第一个句柄,这个句柄在UI的for循环中,直接被销毁了,图中绿色和黄色的句柄,导致循环第二次进入时已经没有句柄了。

所以tab.aardio文件就会报错了。


最新回复 (1)
  • 光庆 19小时前
    0 2

    分析的这么详细,费心了 

返回