Geoff Chappell - Software Analyst
Attempts to build even some startlingly simple VxD projects using common versions of Microsoft’s COFF linker may fail with the following error message:
LINK : error : Internal error during ParseDefDescription
This internal error means that an exception has occurred after entry to the ParseDefDescription function but before the linker gets round to recording that it has progressed to some other function. (Strictly speaking, this ParseDefDescription function is known by that name only for the purpose of reporting errors. Whether the function is called by that name in Microsoft’s source code is of no interest here.)
Inspection reveals a coding error that executes soon after the ParseDefinitionFile function calls the ParseDefDescription function. This call occurs only when using a module definition file that has a non-empty DESCRIPTION entry. The erroneous instruction executes only if /vxd is given on the linker’s command line. The VxD case gets special treatment in that a DESCRIPTION in the module definition file for a VxD is translated to a /comment switch as if for the linker’s command line. (Note that what counts for determining whether the linker is building a VxD rather than some other executable is the /vxd switch on the command line, not a VXD directive in the module definition file.)
At the time the bug occurs in the ParseDefinitionFile function, the DESCRIPTION text has been extracted from the module definition file and duplicated to a heap block A /comment switch is then to be built on the stack before adding it to the translations of module-definition statements. The intention behind the bug is to ensure that this construction of the /comment switch does not overrun its allowance of 80h bytes of stack space. The switch, its colon and a pair of double quotes to enclose the DESCRIPTION text total 11 bytes, leaving 75h bytes for the text, including its terminating null. The bug is that the code puts a null terminator exactly 75h bytes from the start of the text—while the text is still on the heap. In practice, the text for a DESCRIPTION is surely never anything like that long, so the immediate result is a one-byte corruption further into the heap.
The practical result varies widely, depending on the state of the heap at the time of execution. It may often be that this write out-of-bounds is entirely harmless because the corruption site lies either in free space or in space that the program happens to have finished using (and won’t actually look at again).
The next best outcome is for the spurious instruction to trigger the internal error immediately. This can happen if the heap block with the value of the DESCRIPTION entry happens to be very near the end of the last page for which physical memory has yet been committed to the linker’s heap. In this situation, executing the instruction causes a page fault, which the linker handles by reporting the internal error and then terminating.
If the corruption site lies in another heap block or in a header used for defining blocks on the heap, then the consequences are essentially unpredictable. Again, it may happen that the corruption goes unnoticed—for instance, because the heap allocation routines may turn out to meet all subsequent demand for heap space without having to examine the heap headers all the way to the corrupt one. At the other extreme are theoretical possibilities such as more exceptions (but with the internal error ascribed to the wrong function) and incorrect data being calculated for the output files.
Since this can “impact” only on VxD programmers, it’s hardly surprising that the bug has lingered. It is present in the LINK.EXE version 2.60.5046 supplied with the Windows 95 DDK and in versions 3.00.5270, 3.10.6038 and 4.20.6164 from Microsoft Visual C++ 4.0, 4.1 and 4.2 respectively.
The bug is fixed in the LINK.EXE version 5.00.7022 supplied with Microsoft Visual C++ version 5.0. The new code does not proceed with its attempted truncation of the DESCRIPTION text after 75h bytes without checking first that the text is at least that long.
To side-step this bug, avoid using a DESCRIPTION entry in any module definition file for a VxD. Instead, put the description into a /comment switch on the command line, thereby saving LINK from the work that triggers the bug.
Even now that Microsoft has detected the bug and corrected it for new versions, it should be borne in mind that it is not always possible for programmers to insist on particular versions of development tools. This applies especially when source code is written for others—for instance, when a consultant or contractor starts a project that may thereafter be maintained by the client, or when sample code is written for the instruction of and possible adaptation by unknown readers. In the absence of any good reason to insist on Visual C++ 5.0 (or higher), the greater benefit must come from adopting the work-around as standard practice for VxD Programming.