Getting MS-DOS games to run on Windows 95: Too much EMM memory


A report arrived on an MS-DOS game that crashed when run on Windows 95. Mind you, the game ran for quite a while before finally keeling over. The repro steps were "Start the game, then go to City 1, then City A, then City Alpha, then City 𓀀, then City ⛄. When you go to City ⛄, the game crashes."

I gotta say: Our testers were quite thorough.

The reason for the failure is that the program saw too much EMM memory.

Well, not exactly.

Each time you move to a new city, the program tries to allocate some more EMM memory. Under normal conditions, it runs out of EMM memory at some point and presumably starts swapping data out to disk.

What happens when run under Windows 95 is that when you move to the fifth city, the program makes its 65th request for EMM memory. And under Windows 95, the call succeeds, because Windows 95 tries to be all awesome like that. The program then saves that EMM memory handle into a table. The table is a fixed size.

That fixed size is 64 EMM handles.

The program worked when running under MS-DOS because the MS-DOS EMM386 driver defaults to 64 EMM handles, so when the program makes its 65th request for EMM memory, it gets the error "no more EMM handles available." But when run under Windows 95, the program successfully allocates a 65th EMM handle, then adds it to the array, resulting in a buffer overflow. And just our luck, the variable stored immediately after the array holds the location of the EMM page frame.

As a result, when the program tries to copy memory into or out of the EMM page frame, it instead copies memory into and out of some random address. This quickly leads to scrambled memory and the program crashes spectacularly.

Of course, once you know what the problem is, the fix is simple: Limit the program to at most 64 EMM handles.

Comments (16)
  1. Jorge says:

    On a completely unrelated note... I'm intrigued why DebugBreak() stopped working in Windows 8. Back in Windows 7 for DebugBreak() to launch Visual Studio debugger we needed to turn off Windows problem reporting but with Windows 8 that doesn't help either. Do you know whay it is so? Sometimes when troubleshooting a native Windows or COM service there's nothing as eficient as seeding DebugBreak().

  2. Erik F says:

    This program could have had a problem with more than just EMM386: according to the spec, 64 handles was the *minimum* required, but up to 255 handles (128 in EMS 3.2) were allowed. Looking at an old issue of PC Magazine from 1989, most EMS boards allowed you to configure up to 255 handles, although there were some broken implementations that supported less than 64 handles (EMM386 can be configured with as few as 2 handles if you really want.)

    As to why the program hardcoded a 64-entry array, it appears that EMS 3.2 didn't have any way of finding the maximum handle count (http://nersp.nerdc.ufl.edu/~esi4161/files/dosman/chap10); EMS 4.0 introduced INT 67/5402 (GET HANDLE DIRECTORY/GET TOTAL HANDLES SUBFUNCTION), but it doesn't seem to be used much.

    1. Sure, the app doesn't know the maximum, but it could have said "Whoa, my table is full. Don't ask for any more. I won't have anywhere to put it!"

      1. smf says:

        Have you ever met a game developer?

        1. xcomcmdr says:

          What's that supposed to mean ?

          1. smf says:

            Game developers don't check for failure, console game developers especially so.

          2. Mason Wheeler says:

            I guess you must know different game developers than I do...

          3. smf says:

            >I guess you must know different game developers than I do…

            That is statistically certain. However I don't believe my experience is unique. I've been told that trying to handle unforeseen circumstances is heavily frowned upon by. If you spend time and memory trying to handle a situation that you cannot test then how can you be sure that you've handled it correctly?

            The situation is even worse now that a game only needs to barely work before it's mastered and the first online update will be published before it hits the shelves. Sometimes the strategy doesn't pay off, sometimes it does.

      2. Dave Bacher says:

        Maybe the DOS game was intended to be run from a boot disk, and had it configured for the number of handles it wanted.

        It wasn't uncommon to see multiple boot configurations on DOS. It wasn't uncommon to have to boot off the first disk on DOS. It was common enough that eventually, Microsoft added a command line tool to load Himem and Emm386, because some things wanted them, some things didn't, and some things wanted specific switches.

        It's been a while, but I seem to recall a push / pop as well -- but that may have been QEMM and/or PC-DOS as well, IBM had a lot in PC Dos 7 that Microsoft did not.

        1. Considering that the game involved cities, and what I know of popular DOS games that involved cities, none of them involved boot disks or asked their users to create them (or shipped bootable disks for that matter).

  3. guest says:

    "I gotta say: Our testers were quite thorough."

    Yes... I'm sure the person who discovered this was thoroughly "testing" how well the game ran on the new OS, for "testing" purposes. :P

    1. Falcon says:

      Although, of course, testing a game and playing it for entertainment can be very different experiences...

  4. DWalker says:

    "... under Windows 95, the call succeeds, because Windows 95 tries to be all awesome like that. "

    Windows 95 had a lot of awesomeness for its time!

    1. Ray Koopa says:

      You could say... so much awesomess that some old games couldn't deal with it *puts on sunglasses* *The Who music is heard*

      1. Karellen says:

        Or even, "so much awesomeness that some old games couldn’t... *puts on sunglasses* /handle/ it!" (Yeeeeeah!!! BOWMMMM!)

  5. jgh says:

    I had a debugging experience a bit like that. A program that quit almost silently as soon as it was run. I could just tell that something was flashing up before it quit, I eventually ran it enough times quickly enough that I noticed 'buffer overflow' before it quitting and clearing the screen. Knowing what to look for, I spooled the screen output to disk and noticed the string 'Disk free' just before it quit.

    Turns out it was reading the disk free space and trying to display it as some fixed number of digits. The user just happened to have a huuuuuge 110M drive and the authors hadn't anticipated trying to display a free space larger than 99,999,999 bytes. Easy solution: a startup script that created a 10M dummy file to drop the free space below 100M.

Comments are closed.

Skip to main content