Improper AddTimer script causes program crash.

Posted by Magnum on Wed 19 Dec 2001 06:19 AM — 7 posts, 19,114 views.

Canada #0
Wow. I actually found a way to make the program crash.

MUSHCLIENT caused an invalid page fault in
module <unknown> at 0000:00000001.
Registers:
EAX=00000000 CS=017f EIP=00000001 EFLGS=00010202
EBX=00000000 SS=0187 ESP=007afa84 EBP=01013778
ECX=017563f0 DS=0187 ESI=007afa88 FS=29a7
EDX=017563fc ES=0187 EDI=01013294 GS=0000
Bytes at CS:EIP:
01 00 00 00 04 70 00 16 00 29 0c 65 04 70 00 65
Stack dump:
0040ca3f 00000001 01100340 01013294 007afb7c 00461100 017563f0 01044c88 3c202c95 00000000 007afa88 007afac0 00000000 00000001 00000000 00000000

The IPF was caused by the following script routine:

Sub Inventory_Full (thename, theoutput, thewildcards)
If World.GetVariable("HaveSlave") Then
If World.GetVariable("SlaveFull") Then
World.AddTimer "SlaveSellTimer", 0, 0, 2, CStr(thewildcards(1)), 5, "Slave_Sell_All"
Else
World.AddTimer "SlaveTakeTimer", 0, 0, 2, CStr(thewildcards(1)), 5, "Slave_Take_All"
End If
End If
End Sub

Specifically, the AddTimer lines.

I call this script when, during mud play, I attempt to pick up items, but can not because my inventory is full. I decided to delay calling of the two script routines, because often I would try and pick up multiple items at once, and therefor this subroutine would be called multiple times in quick succession. Adding a timer resloves the issue, by preventing the client from sending repetitive commands to the mud regarding my slave. (I just send multiple AddTimer requests, but since they all have the same name, only one timer is created, and the commands in the routines they call are only executed once)

I assume my error in the subroutine was not to pass paramters. I am still researching the answer to this script bug...
Australia Forum Administrator #1
I tried the AddTimer line in immediate mode without a crash. What do you mean by "not to pass parameters" - do you mean the Slave_Sell_All routine did not accept parameters? You seem to be passing parameters to AddTimer.

What I tried was:


World.AddTimer "SlaveTakeTimer", 0, 0, 2, CStr("blah"), 5, ""
Canada #2
I worked out the bug in my script to get it working. Before I post by script tidbits, I should point out that I crashed mushclient again a slightly different way, and got this Windoze error dump:

MUSHCLIENT caused an invalid page fault in
module MUSHCLIENT.EXE at 017f:0049377a.
Registers:
EAX=007afcfc CS=017f EIP=0049377a EFLGS=00010213
EBX=00680a8c SS=0187 ESP=007afcd8 EBP=007afd04
ECX=01101d20 DS=0187 ESI=7706ab5d FS=22f7
EDX=00000002 ES=0187 EDI=01101d20 GS=0000
Bytes at CS:EIP:
8b 3e 85 ff 75 28 8b 46 04 53 8b 59 08 33 d2 c1
Stack dump:
01101d20 01101d00 0049af68 007afcfc 007afcf8 007afd00 00000001 00000000 00000782 7706ab5d 01012eb4 007afd18 0049ad6d 00000001 0050cda8 00000000

Here's my revised script, with a few other routines shown:

Sub Slave_Sell_All (thename, theoutput, thewildcards)
World.Send "ssell all"
SlaveFull_False "Slave_Sell_All", "-", "-"
End Sub

Sub Slave_Sell_All_From_Timer (TimerError)
Slave_Sell_All "Slave_Sell_All_From_Timer", "-", "-"
End Sub

Sub Slave_Take_All (thename, theoutput, thewildcards)
World.Send "ssummon"
World.Send "gives all"
World.Send "sstop"
End Sub

Sub Slave_Take_All_From_Timer (TimerError)
Slave_Take_All "Slave_Take_All_From_Timer", "-", "-"
End Sub

Sub Inventory_Full (thename, theoutput, thewildcards)
If World.GetVariable("HaveSlave") Then
If World.GetVariable("SlaveFull") Then
World.AddTimer "SlaveSellTimer", 0, 0, 2, "", 5, "Slave_Sell_All_From_Timer"
Else
World.AddTimer "SlaveTakeTimer", 0, 0, 2, "", 5, "Slave_Take_All_From_Timer"
End If
End If
End Sub

This second crash occurred when I did NOT put the "(TimerError)" parameter on the '_From_Timer' routines.

If you have a keen eye, you'll notice I dropped the wildcards sending in this latter script. It shouldn't have been in the first one, I forgot to remove it when I cut and wasted the AddTimer command from elsewhere.
Australia Forum Administrator #3
I have added this as bug #430.

However you are correct that a timer script routine should take a formal argument, namely the timer name. This is so that a single script routine can be shared by multiple timers.
Canada #4
Dang, you are fast Nick. :) ...I hadn't even read your reply when I posted a reply to myself above.

The point is: The AddTimer function is quite vulnerable to parameter errors, which will cause the program to crash.

- Passing the wrong amount of parameters to AddTimer will cause a program crash.

- Calling a script routine from a timer, and that routine not accepting a parameter will cause a program crash.
Australia Forum Administrator #5
This is really a vulnerability of the scripting interface, over which I do not have a great deal of control (it is done with COM).

I can detect whether or not a particular script routine exists (you have probably seen error messages if you add a trigger which calls a non-existent script), however I can't easily detect whether the number of arguments the script routine will take agrees with the number I intend to supply.
Australia Forum Administrator #6
I have fixed this in 3.18. It seems the timer was deleted (as it was a one-shot timer) while you were looking at the dialog box about "wrong number of arguments". Then the deleted timer caused a crash when you closed the dialog box. I have worked around that problem.