***** BUG REPORT ***** ***** MAJOR BUG IN TURBO PASCAL V2.00 ***** July 1,1984 (updated December 1984) The runtime routines do not handle a floating-point (real) subtraction correctly. For some subtractions, the correct difference is returned; for others, a zero is returned. The following program demonstrates the bug: program test; begin writeln(9.+(-6.0)); { Wrong value returned } writeln(-1.0+(-1.0)); { Correct value returned } writeln(1-2); { Correct value returned } writeln(1.-2:10:2); { Wrong value returned } writeln(1.-2.0); { Wrong value returned } writeln(1-2.0); { Wrong value returned } writeln(456 - 123.0); { Correct value returned } end. A value of zero is returned on those lines marked as 'wrong'. The other lines return the correct difference. VERSIONS TESTED AND FOUND OK (December 1984) The following versions of Turbo have been checked for this bug and are alright. Any versions for same OS, with higher serial numbers, should be alright--but use the above test program to be sure. The bug may be unique to MS-DOS versions. Turbo ver 1.01A for CP/M-86 serial # 1225 Turbo ver 2.00B for CP/M-86 serial # 49036 Turbo ver 2.00B for MS-DOS serial #131821 THE CAUSE After disassembling and tracing through a sample compiled program, the error was located in the following code: XXXX:12FA E84FFF CALL 124C ; Subtract XXXX:12FD 7306 JNB 1305 XXXX:12FF 80F780 XOR BH,80 ; Handle negative XXXX:1302 E863FF CALL 1268 ; numbers XXXX:1305 8B4504 MOV AX,[DI+04] ; Is mantissa zero? XXXX:1308 0B4502 OR AX,[DI+02] XXXX:130B 0A4501 OR AL,[DI+01] ; ***** ERROR ***** XXXX:130E 740D JZ 131D ; Yes XXXX:1310 F6450580 TEST BYTE PTR [DI+05],80 ; Normalize XXXX:1314 750C JNZ 1322 (Comments have been added for clarity). This disassembled code is located in the routines that handle addition and subtraction (only the subtraction part is shown). The error occurs when the routine tests to see if the result of the subtraction is zero. It tests for a zero by "OR-ing" together the five bytes of the mantissa (the instructions that do this are at offsets 1305H to 130BH). If the mantissa is zero, then the result of this "multiple-or" will set the zero flag. The first of these instructions is a move of the word at [DI+4] to AX. The next instruction takes the logical OR of AX and [DI+2]. No problem so far. However, the last instruction is "OR AL,[DI+1]", an instruction that operates on a byte and not on a word. If the OR of the words at [DI+4] and [DI+2] results in a word whose UPPER byte is NONZERO but whose LOWER byte is ZERO, then the next instruction, the "byte-wise" OR, will SET the zero flag if the byte at [DI+1] is zero. Notice that the instruction at 130BH totally ignores the contents of the upper byte of AX; the flags are set according to the lower byte of AX only. This is what causes the error. THE FIX The fix to this bug is simple: simply exchange the order of the two "OR" instructions. This way, the zero flag is set according to a full 16-bit OR and not an 8-bit one. IMPORTANT: Only persons familiar with the operation of DEBUG should attempt the following. Using DEBUG, the following sequence of commands can be used to fix the bug: Assumptions and notes in the following: 1) ONLY WORK ON A COPY OF TURBO! DO NOT USE YOUR MASTER COPY! 2) The sequence of commands shown below writes out the fixed version to the file 'turbo.com' 3) Make sure that you have version 2.00 4) 'turbo.com' must be in the current directory on drive B. 5) DOS 2.00 or above is being used (the debugger in DOS 1.00 and 1.10 does not have the 'assemble' command). 6) Be sure to verify that the code in the compiler is the same as that shown below initially. After the changes are made, be sure to verify that the changes have been made correctly before writing the fixed version out to disk. B>debug turbo.com -u 12fa <- Verify the following locations XXXX:12FA E84FFF CALL 124C XXXX:12FD 7306 JNB 1305 XXXX:12FF 80F780 XOR BH,80 XXXX:1302 E863FF CALL 1268 XXXX:1305 8B4504 MOV AX,[DI+04] XXXX:1308 0B4502 OR AX,[DI+02] XXXX:130B 0A4501 OR AL,[DI+01] XXXX:130E 740D JZ 131D XXXX:1310 F6450580 TEST BYTE PTR [DI+05],80 XXXX:1314 750C JNZ 1322 XXXX:1316 E8F9FE CALL 1212 XXXX:1319 FE0D DEC BYTE PTR [DI] -a 1308 <- Make changes XXXX:1308 or al,[di+1] XXXX:130E or ax,[di+2] XXXX:1311 <- Press 'enter' -u 12fa <- Verify that the changes are correct XXXX:12FA E84FFF CALL 124C XXXX:12FD 7306 JNB 1305 XXXX:12FF 80F780 XOR BH,80 XXXX:1302 E863FF CALL 1268 XXXX:1305 8B4504 MOV AX,[DI+04] XXXX:1308 0A4501 OR AL,[DI+01] XXXX:130B 0B4502 OR AX,[DI+02] XXXX:130E 740D JZ 131D XXXX:1310 F6450580 TEST BYTE PTR [DI+05],80 XXXX:1314 750C JNZ 1322 XXXX:1316 E8F9FE CALL 1212 XXXX:1319 FE0D DEC BYTE PTR [DI] -w <- Save fixed version of turbo Writing 8E80 bytes -q B> OTHER NOTES ABOUT TURBO One cannot set breakpoints in TURBO using DEBUG. It seems that TURBO uses the breakpoint interrupt for some hideous reason. If one attempts to set breakpoints, the system will probably crash. Tracing, however, does seem to work. The above bug was tracked down only after hours of tracing (by machine and by hand) and disassembling. --------