possible data corruption while scrolling through rows

abel deuring <[email protected]> Mon, 17 Jan 2005 00:22:17 +0100
Newsgroups gmane.comp.db.rekall.devel
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--------------040908050805060203090304
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

hi,

I noticed the following bug in Rekall (I'm using version 2.2.3):

If a form block has a sub block, it can happen that the contents of some 
rows of the sub block is deleted, when the user presses for example the 
up or down arrow quickly two or more times in the parent block. (The 
problem may perhaps also occur for a simple form block, if row updates 
take a long time -- I didn't read the sources carefully enough to tell 
for sure...)

At some time during a call of KBFormBlock::doOperation e.g. for a down 
arrow keystroke, a progress bar is opened, and TKProgress::setDone calls 
qApp->processEvents. If the next key stroke arrives in the event queue 
before this call, processEvents causes another call of 
KBFormBlock::doOperation. The problem now is that 
KBFormBlock::doOperation is not reentrant safe. It happened to me quite 
often, that the first call of KBFormBlock::doOperation was at the point, 
where KBControl::clearValue() has been called, but where 
KBControl::getIniValue returns a non-empty value. Hence, during the 
second call of doOperation, KBControl::changed returns true, and all 
values of the affected row are deleted.

I fixed this (more or less...) by not allowing recursive calls of 
doOperation. See the attached patch. It detects recursive calls and 
queues them so that the "real execution" can be deferred until the first 
call of doOperation is finished. This may lead to an unexpected 
behaviour, because the execution sequence for events can be changed, if 
events are queued for different block at the same time. Any comments?

Abel

--------------040908050805060203090304
Content-Type: text/plain;
 name="kb_formblock.h.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="kb_formblock.h.diff"

--- rekall-2.2.3-orig/libs/kbase/kb_formblock.h	2004-11-18 19:26:23.000000000 +0100
+++ rekall-2.2.3/libs/kbase/kb_formblock.h	2005-01-17 00:14:49.000000000 +0100
@@ -24,6 +24,14 @@
 /*  -----------								*/
 /*  This class implements the block object when embedded in a form.	*/
 
+typedef struct	_opList
+{
+	KB::Action	action;
+	uint		toQRow;
+	KBTabOrderList	*tabList;
+	_opList		*next;
+} _opList;
+
 class LIBKBASE_API	KBFormBlock : public KBBlock, public KBNavigator
 {
 	Q_OBJECT
@@ -47,6 +55,9 @@
 
 	void			focusMovesRow	(uint)			;
 	void			focusMovesItem	(KBItem *, QFocusEvent::Reason) ;
+	bool			_doOperation	(KB::Action, uint, KBTabOrderList * = 0) ;
+	_opList			*queueFirst, *queueLast			;
+	int			inOperation				;
 
 public	:
 

--------------040908050805060203090304
Content-Type: text/plain;
 name="kb_formblock.cpp.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="kb_formblock.cpp.diff"

--- rekall-2.2.3-orig/libs/kbase/kb_formblock.cpp	2004-11-18 19:26:23.000000000 +0100
+++ rekall-2.2.3/libs/kbase/kb_formblock.cpp	2005-01-16 23:26:43.000000000 +0100
@@ -60,6 +60,9 @@
 	m_curItem  = 0	     ;
 	m_inQuery  = false   ;
 	m_dChanged = false   ;
+	queueFirst = queueLast = 0;
+	inOperation = 0	     ;
+	
 
 	if ((dx.getIntValue() == 0) && (dy.getIntValue() == 0))
 			dy.setValue (25) ;
@@ -92,6 +95,8 @@
 	m_curItem  = 0	     ;
 	m_inQuery  = false   ;
 	m_dChanged = false   ;
+	queueFirst = queueLast = 0;
+	inOperation = 0	     ;
 }
 
 /*  KBFormBlock								*/
@@ -115,6 +120,8 @@
 	m_curItem  = 0	     ;
 	m_inQuery  = false   ;
 	m_dChanged = false   ;
+	queueFirst = queueLast = 0;
+	inOperation = 0;     ;
 }
 
 /*  KBFormBlock								*/

--------------040908050805060203090304
Content-Type: text/plain;
 name="kb_blockact.cpp.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="kb_blockact.cpp.diff"

--- rekall-2.2.3-orig/libs/kbase/kb_blockact.cpp	2004-11-18 19:26:23.000000000 +0100
+++ rekall-2.2.3/libs/kbase/kb_blockact.cpp	2005-01-17 00:16:32.000000000 +0100
@@ -120,9 +120,49 @@
 		KBTabOrderList	*tabList
 	)
 {
+	if (inOperation)
+	{
+		_opList *p = (_opList*) malloc(sizeof(_opList));
+		if (!p) 
+			return false;
+		
+		if (!queueFirst)
+			queueFirst = p;
+		else
+			queueLast->next = p;
+		
+		p->action = action;
+		p->toQRow = toQRow;
+		p->tabList = tabList;
+		p->next = 0;
+		queueLast = p;
+		
+		return true; // xxx problematisch...
+	}
+	
+	inOperation++;
+	bool res = _doOperation(action, toQRow, tabList);
+	
+	while (queueFirst)
+	{
+		_opList *p = queueFirst;
+		_doOperation(p->action, p->toQRow, p->tabList);
+		queueFirst = p->next;
+		free(p);
+	}
+	inOperation--;
+	return res;
+}
+
+bool	KBFormBlock::_doOperation
+	(	KB::Action	action,
+		uint		toQRow,
+		KBTabOrderList	*tabList
+	)
+{
 	if (action == KB::Reload)
-		return	doOperation (KB::Query,   0, tabList) &&
-			doOperation (KB::Execute, 0, tabList) ;
+		return	_doOperation (KB::Query,   0, tabList) &&
+			_doOperation (KB::Execute, 0, tabList) ;
 	/* If the block is a null (menu-only) block then there is	*/
 	/* nothing to do within this block, but we do scan down through	*/
 	/* any nested form blocks or framers.				*/

--------------040908050805060203090304
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Rekall-devel mailing list
[email protected]
http://www.mailman.a-i-s.co.uk/cgi-bin/mailman/listinfo/rekall-devel
--------------040908050805060203090304--