Back to Homework

Mobius strip

Bugs and Anomalies encountered in HW15

This entire page is optional reading.

Zach's TSR Status: Completed and stable

Text appear normally when I type at the command line. Pressing F1 produces a red "HI!" in the upper-right corner. Pressing F2 prints "BYE" in the same place. F3 disables F1 and F2 until F3 is pressed again. (I say "stable", but I don't think I'd guarantee it!)

Bug hunt: Why my program was crashing.

This one took me hours to track down. Here's the story, for those who are interested in an example of bug hunting:

The problem is that the program continues to crash--usually after 4 to 20 keypresses. It does this in an exciting variety of ways--silently, with an illegal instruction error, with strange attempts to access BIOS ROM, and by crashing the entire ntvdm (the DOS virtual machine under Windows XP). Impressively, Windows XP has been entirely unphased by this behavior. As of yet, I have not been able to track down this bug.

Because of it's random nature, it seems the bug is due to trying to process garbage instructions. As an example of hairy, brute-force debugging, here the things I've checked. (Sorry I can't share my code yet.)

The original vector is saved correctly.
Keypresses appear "normally" on the command line when I invoke the saved vector (until the whole TSR crashes). [But see the Anomalies section, below.]
The size of the code left in memory is sufficient.
I have added up to 32 extra paragraphs, and it does not fix the problem. (The bug seemed like it might be caused by later programs and DOS calls overwriting my code in memory.)
Turning on or off the interrupt flag.
It doesn't seem to be other interruptions throwing off my system state.
Not calling the original vector handler.
The code does not crash, though I can only print something on the first keypress. Future keypresses do not bring about a crash.
  • Adding 1 to the column each time I print, I find I only print for the first keypress if I do not call the original handler. After the first press, no response.
  • If I do call the old handler, I get two (?!) increments. And the crashing starts again.
Calling only the original vector handler.
FKeyHandler is my resident function. If it contains only this:
FKeyHandler	PROC
	pushf
	call 	KbdHandler
	iret
FKeyHandler	ENDP
I get no crashes. Characters appear on the command line. (Removing pushf gets me consistent crashes on the first keypress, so that's definitely required.)

If I add any code, like this:

FKeyHandler	PROC
	push 	cs
	pop	ds
	pushf
	call 	KbdHandler
	iret
FKeyHandler	ENDP
I get crashes again. Interestingly, if I push and pop ds, I get no crashes! [I was prompted to try this so that the two added lines changed nothing about the state to see if it still crashed.]

Following up on this ds hint, I removed the lines:

	push	cs
	pop	ds
from the resident part of my code. (I still use it in the setup part of my code.) This fixed the problem!

I still don't understand why though:

  • I have only one segment--hence the need in the setup part of setting ds == cs.
  • If I remove it from the setup code, I get a consistent crash on the first keypress. This makes sense, since I make ds == cs and then use ds as the destination segment when I replace the 09h vector.
  • I only have one .CODE statement, so the code segment should have the same value for both the resident and setup subroutines.
  • Pager's code does this in both the setup and the resident part without ill effect. (Removing it from the resident part of greet.asm means it prints garbage instead of HI! and BYE.)
  • I can even run another program (the delay demo from project 2)--which would surely change the contents of the ds and cs registers--but my TSR continues to run fine afterwards.

So, long story short, when my resident code runs, it magically knows where my data is--which includes the location of the original keyboard vector function, as well as my HI! and BYE strings. If I explicitly make ds point to where (I think) it should--the same segment as the TSR code the 09h vector now points to--I get random crashes.

Remaining Anomalies

The NTVDM gremlin.
We're not really running in "real" DOS mode, but in a protected virtual machine environment. So certain magic is happening. The computer doesn't lock up when an assembly program crashes or messes up a vector. Windows is still intercepting some keypresses before they even get to DOS--Ctrl+Alt+Del, Alt+Tab, the Windows key, etc. And something else resets the 09h keyboard vector pointer for me when my TSR crashes. (How does it know to do that?) What else is it doing for me that I might not want it doing?
Replacing the 09h vector, but then immediatedly calling it from the TSR, still stops DOS's Fn keys from working.
(Also stops the up and down arrows cycling through the command history.) This continues to baffle me, since it seems I should be replicating normal DOS behavior if the only thing I do is call the original handling function. Also, having the TSR intercept things adds a lag to keyboard--more than makes sense for a single function call.
After pressing F2, the next regular keypress (a letter, Enter, etc.) is ignored.
This doesn't affect F1 or F3. Is this a ghost of DOS's F2 functionality, which waits for a keypress?
A keyboard listener that does not call the original keyboard vector will only print something on the first keypress.
Why doesn't it work for every keypress?
Calling the original keyboard vector and then printing something means that something will be printed twice.
I'm am now pretty sure this is due to how keys are handled, as per scan codes--there's one call for pressing the key down and another for when it is released. It seems the 09h vector is being called once for each of them.


~ztomasze Index : TA Details : ICS312 : TSR Help
http://www2.hawaii.edu/~ztomasze
Last Edited: 03 Mar 2006
©2006 by Z. Tomaszewski.