 |
Vijilante SubAdmin

Joined: 18 Nov 2001 Posts: 5187
|
Posted: Sun Nov 04, 2007 12:18 am
[2.10] UNVAR crash (not thread safe) |
I initially tested this with a longer procedure that produced a crash at a different point, but I haven't been able to replicate that crash point. I also had the final step not cause a crash in some of tests, but repeating that step soon caused a crash.
Procedure
1. Launch CMud
2. Close Sessions window (ESC)
3. Enter at the command line
| Code: |
| #WHILE 1 {#ADD a 1} |
4. Hit SHIFT-ESC to put the while into the background
5. Enter at the command line
The first crash is the replicatable one. I am also including the one I could not replicate, which appears to be a timing issue.
| Code: |
date/time : 2007-11-03, 20:30:12, 39ms
operating system : Windows XP Service Pack 2 build 2600
system language : English
system up time : 15 days 12 hours
program up time : 43 seconds
processor : AMD Athlon(tm) Processor
physical memory : 165/383 MB (free/total)
free disk space : (C:) 14.90 GB
display mode : 1024x768, 32 bit
process id : $633c
allocated memory : 42.87 MB
executable : cMUD.exe
exec. date/time : 2007-11-02 17:51
version : 2.10.0.0
madExcept version : 3.0b
callstack crc : $7bb5fe5f, $84a7275e, $e6ec8a1e
count : 3
exception number : 1
exception class : EAccessViolation
exception message : Access violation at address 00D32045 in module 'cMUD.exe'. Read of address 0000005C.
untitled Comline ($8a20):
00d32045 +015 cMUD.exe PrefDat 7806 +1 PrefRec.GetOption
00d3656c +0f8 cMUD.exe PrefDat 9355 +7 PrefRec.LoadCache
00d36379 +015 cMUD.exe PrefDat 9301 +1 PrefRec.GetArgList
00d36857 +023 cMUD.exe PrefDat 9408 +1 PrefRec.SetArgList
00d46836 +486 cMUD.exe CodeExec 1712 +86 HandleAssign
00d48d36 +626 cMUD.exe CodeExec 2417 +84 HandleCom
00d4a9e6 +5b2 cMUD.exe CodeExec 2951 +96 TCodeExec.InternalExecute
00d42341 +071 cMUD.exe CodeExec 451 +9 TCodeExec.Execute
00d48a06 +2f6 cMUD.exe CodeExec 2360 +27 HandleCom
00d4a9e6 +5b2 cMUD.exe CodeExec 2951 +96 TCodeExec.InternalExecute
00d4227e +05e cMUD.exe CodeExec 427 +8 TCodeExec.Execute
00c4c49c +154 cMUD.exe CodeThread 1534 +21 TRunCodeThread.Run
00903bec +138 cMUD.exe IdThread 360 +47 TIdThread.Execute
0047d9da +036 cMUD.exe Classes 9372 +7 ThreadProc
00405acc +028 cMUD.exe System ThreadWrapper
Main ($6334):
7c90eb94 +00 ntdll.dll KiFastSystemCallRet
0052edb9 +1d cMUD.exe Forms 6862 +2 TApplication.ProcessMessage
0052ee8f +0f cMUD.exe Forms 6892 +1 TApplication.HandleMessage
0052f12a +a6 cMUD.exe Forms 6976 +16 TApplication.Run
00dbda08 +88 cMUD.exe CMUD 344 +18 initialization
7c91312f +69 ntdll.dll RtlUnicodeStringToAnsiString
7c812907 +b6 kernel32.dll GetVersionExA |
| Code: |
date/time : 2007-11-03, 20:22:04, 257ms
computer name : CHAOTIC
user name : James Dean <admin>
operating system : Windows XP Service Pack 2 build 2600
system language : English
system up time : 15 days 12 hours
program up time : 1 minute 46 seconds
processor : AMD Athlon(tm) Processor
physical memory : 180/383 MB (free/total)
free disk space : (C:) 14.90 GB
display mode : 1024x768, 32 bit
process id : $c54c
allocated memory : 28.62 MB
executable : cMUD.exe
exec. date/time : 2007-11-02 17:51
version : 2.10.0.0
madExcept version : 3.0b
callstack crc : $47a2947b, $7eed0c3a, $7eed0c3a
exception number : 1
exception class : EDatabaseError
exception message : MemCursor: Dataset is not in edit mode.
Main ($2e20):
006400fe +006a cMUD.exe DB 2350 +2 DatabaseError
00663392 +006a cMUD.exe kbmMemTable 11007 +5 TkbmCustomMemTable.SetFieldData
00650593 +0047 cMUD.exe DB 9250 +2 TDataSet.SetFieldData
008deaa1 +0029 cMUD.exe ZAbstractRODataset 1170 +3 TZAbstractRODataset.SetFieldData
0064405f +008b cMUD.exe DB 4003 +4 TField.SetData
006452fc +010c cMUD.exe DB 4447 +14 TStringField.SetAsString
0065051c +0100 cMUD.exe DB 9238 +16 TDataSet.GetFieldData
00650463 +0047 cMUD.exe DB 9224 +2 TDataSet.GetFieldData
0064405f +008b cMUD.exe DB 4003 +4 TField.SetData
006452fc +010c cMUD.exe DB 4447 +14 TStringField.SetAsString
00650463 +0047 cMUD.exe DB 9224 +2 TDataSet.GetFieldData
00505f93 +01df cMUD.exe Controls 4645 +53 TControl.WndProc
00505c9e +0036 cMUD.exe Controls 4552 +5 TControl.Perform
0050ccf3 +0037 cMUD.exe Controls 7721 +3 TWinControl.CMInvalidate
00505f93 +01df cMUD.exe Controls 4645 +53 TControl.WndProc
004966a8 +000c cMUD.exe SyncObjs 222 +1 TCriticalSection.Leave
0065d369 +0009 cMUD.exe kbmMemTable 6034 +5 TkbmCommon.Unlock
00663594 +026c cMUD.exe kbmMemTable 11083 +81 TkbmCustomMemTable.SetFieldData
0064405f +008b cMUD.exe DB 4003 +4 TField.SetData
006452fc +010c cMUD.exe DB 4447 +14 TStringField.SetAsString
00650463 +0047 cMUD.exe DB 9224 +2 TDataSet.GetFieldData
0064405f +008b cMUD.exe DB 4003 +4 TField.SetData
0048593b +001b cMUD.exe Graphics 1380 +1 TGraphicsObject.Changed
00650463 +0047 cMUD.exe DB 9224 +2 TDataSet.GetFieldData
0064405f +008b cMUD.exe DB 4003 +4 TField.SetData
006452fc +010c cMUD.exe DB 4447 +14 TStringField.SetAsString
004d706e +0d12 cMUD.exe ComCtrls 14625 +276 TCustomListView.CNNotify
004d6c1b +08bf cMUD.exe ComCtrls 14525 +176 TCustomListView.CNNotify
7c912c94 +0013 ntdll.dll LdrFindResource_U
77d5029f +0078 USER32.dll WCSToMBEx
77d6ecc8 +0030 USER32.dll LoadStringA
0082721e +0032 cMUD.exe StDict 546 +5 TStDictionary.DoEqual
0082727c +0050 cMUD.exe StDict 561 +8 TStDictionary.dyFindNode
008274e1 +0035 cMUD.exe StDict 680 +5 TStDictionary.Exists
0064405f +008b cMUD.exe DB 4003 +4 TField.SetData
00645b92 +006a cMUD.exe DB 4646 +4 TIntegerField.SetAsInteger
006429c4 +0088 cMUD.exe DB 3450 +4 TField.AssignValue
00661e8f +00ab cMUD.exe kbmMemTable 9725 +20 TkbmCustomMemTable.FindKey
00d24ce1 +005d cMUD.exe PrefDat 1913 +8 PrefRec.Remove
00d24be3 +000f cMUD.exe PrefDat 1883 +1 PrefRec.Destroy
00d25752 +0032 cMUD.exe PrefDat 2244 +4 VarRec.Destroy
00404be0 +0008 cMUD.exe System TObject.Free
00cc5852 +96b6 cMUD.exe MAIN 18055 +1668 HandleCase
00cc6d3f +007f cMUD.exe MAIN 18181 +11 TMUDForm.ExecCommand
00c4b1ac +0034 cMUD.exe CodeThread 1076 +2 TRunCodeThread.DoExecCommand
0047d901 +0101 cMUD.exe Classes 9339 +22 CheckSynchronize
00c4a3ac +0094 cMUD.exe CodeThread 435 +15 MsgWaitForSingleObject
00c4a4fd +0029 cMUD.exe CodeThread 510 +4 WaitForThread
00c97c52 +012e cMUD.exe MAIN 6005 +32 TMUDForm.ExecThread
00c987e2 +03c6 cMUD.exe MAIN 6213 +44 TMUDForm.NewProcessStr
00c977be +0026 cMUD.exe MAIN 5899 +2 TMUDForm.ProcessStr
00c9729a +004a cMUD.exe MAIN 5774 +12 TMUDForm.ParseCommand
00ca5be3 +0223 cMUD.exe MAIN 11189 +34 TMUDForm.Command
00ca6f14 +0250 cMUD.exe MAIN 11538 +37 TMUDForm.FormKeyDown
00ccdf26 +0012 cMUD.exe MAIN 20058 +1 TMUDForm.UserInKeyDown
0050b5a0 +0030 cMUD.exe Controls 7026 +1 TWinControl.KeyDown
009aa1be +0012 cMUD.exe RVScroll 548 +1 TRVScroller.KeyDown
00958dc5 +0011 cMUD.exe RichView 1842 +1 TCustomRichView.KeyDown
0093539c +0090 cMUD.exe RVEdit 1625 +14 TCustomRichViewEdit.KeyDown
0050b618 +006c cMUD.exe Controls 7043 +10 TWinControl.DoKeyDown
0050b646 +0012 cMUD.exe Controls 7052 +1 TWinControl.WMKeyDown
00935275 +01d5 cMUD.exe RVEdit 1591 +36 TCustomRichViewEdit.WMKeyDown
00505c9e +0036 cMUD.exe Controls 4552 +5 TControl.Perform
0050c3c9 +00dd cMUD.exe Controls 7471 +18 TWinControl.CNKeyDown
00505f93 +01df cMUD.exe Controls 4645 +53 TControl.WndProc
00509cc2 +018e cMUD.exe Controls 6342 +33 TWinControl.WndProc
00509894 +0034 cMUD.exe Controls 6237 +3 TWinControl.MainWndProc
0047fef8 +0014 cMUD.exe Classes 10966 +8 StdWndProc
77d4bcc7 +000a USER32.dll DispatchMessageA
0052ee48 +00ac cMUD.exe Forms 6873 +13 TApplication.ProcessMessage
0052ee8f +000f cMUD.exe Forms 6892 +1 TApplication.HandleMessage
0052f12a +00a6 cMUD.exe Forms 6976 +16 TApplication.Run
00dbda08 +0088 cMUD.exe CMUD 344 +18 initialization
7c91312f +0069 ntdll.dll RtlUnicodeStringToAnsiString
7c812907 +00b6 kernel32.dll GetVersionExA |
|
|
_________________ The only good questions are the ones we have never answered before.
Search the Forums |
|
|
 |
Tech GURU

Joined: 18 Oct 2000 Posts: 2733 Location: Atlanta, USA
|
Posted: Sun Nov 04, 2007 7:44 am |
Confirmed.
|
|
_________________ Asati di tempari! |
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Mon Nov 05, 2007 5:50 pm |
Added to bug list. Probably effects some other #UN commands as well.
|
|
|
|
 |
Zugg MASTER

Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Wed Nov 14, 2007 8:51 pm |
As I thought, all of the #UN... commands are effected by this problem. And this one is a real problem to fix.
The problem is that the #UNVAR command is freeing the internal record for the variable and deleting it from the database. But a thread running in the background might have it's own reference pointing to this internal record. So now suddenly the variable reference in the background thread is pointing to freed memory, causing all sorts of crashes.
This is one thing I've always hated about memory management. It would be nice if the Free routine could somehow mark the memory as freed so that you could trap this in any other access to that part of memory. But since garbage collection could re-use that memory, the background thread pointer might actually point to valid memory...it just isn't the memory used by the variable anymore.
To make matters worse, Windows can switch threads at any time. So anyplace in my code that I have something like this:
Obj := FindVar( VarName)
do something with Obj.Value
then between these two statements, Windows could switch threads and execute an #UNVAR command, which now causes the Obj pointer to be invalid. The above example would be relatively easy to protect with a critical section. But there are other cases that do stuff like "Obj.Execute" to execute an alias reference, and then later access another property of Obj. And I can't put a section around all of that, because "Execute" is something that could take a long time and call all sorts of other routines, which would deadlock the critical section.
I could implement a "deleted objects list" that would keep track of what references are no longer valid. But then I'd have to change *every* reference to the objects to something that searched this list, and this would cause a huge performance decrease.
This is very similar to a past problem we had where a setting would put a refresh message into the Windows message queue, and then the setting was removed before the message was processed. But the solution to this was to delete the refresh message from the queue when the setting was deleted. The #UNVAR case is more complicated and there aren't any Windows messages involved. It's really more of a classic case of two threads accessing the same resource, and one thread deciding to destroy the object.
What I guess I'll need to do is implement a reference counting system for these objects. Then somehow I'll mark an object as "inuse" and then unmark it when I'm done. The Free routine will check to see if the object is in use and just mark it as deleted. Then, when the object's inuse count hits zero, the object will delete itself if needed. But this is going to be very time consuming to implement since I'll have to check *every* access I make to objects that might be freed by the #UN commands. There isn't any way to implement it transparently within the current class code. |
|
|
|
 |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|