KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q42213: Error in Adding Longs Returned by Reference

Article: Q42213
Product(s): See article
Version(s): 5.10   | 5.10
Operating System(s): MS-DOS | OS/2
Keyword(s): ENDUSER | buglist1.01 fixlist2.00 buglist5.10 | mspl13_c
Last Modified: 16-JAN-1990

The program below does not properly perform the addition specified
when compiled for the compact- or large-memory model.

Any time three or more numbers are added (e.g in the example below)
all values between the first and last number are incorrectly added.
The workaround is to use temporary variables as necessary.

Microsoft has confirmed this to be a problem in Version 1.01 and 5.10.
This problem was corrected in Version 2.00.

The following code demonstrates the problem:

    #include <stdio.h>

    void     * foo( long * num );

    void * foo( long * num )
    {
        return( (void *) num );
    }

    void main()
    {
        long num1  = 100,
             num2  = 200,
             num3  = 300,
             total = 0;

        total = * (long *) foo( &num1 ) +
                * (long *) foo( &num2 ) +
                * (long *) foo( &num3 );
        if (total != 600)
        {
            printf("Did not compute.\n");
        }
    }

The addition is performed incorrectly because of the manner in which
the compiler generates code to handle the intermediate value obtained
by dereferencing the pointer returned by foo( &num2 ). In compact
model, the relevant assembly code appears similar to the following:

    .
    .
    .
    mov     ax, word ptr es:[bx]        ; here we dereference &num2
    mov     word ptr [bp-22], ax        ;     storing the 200
    mov     ax, word ptr es:[bx+2]      ;     in bp-22
    mov     word ptr [bp-20], ax        ;     and bp-20
    .
    .
    .
    mov     word ptr [bp-24], es    ; store segment of &num2 (this was
                                    ; moved into es after being
                                    ; returned in dx earlier)
    call    _foo                        ; passing &num1 this time
    add     sp, 4
    mov     bx, ax                      ; es:bx holds address of num1
    mov     es, dx                      ; returned from foo
    mov     ax, word ptr es:[bx]        ; dereference address of
    mov     dx, word ptr es:[bx+2]      ; num1, store in ax, dx
*   mov     bx, word ptr [bp-24]        ; here's the bad one:  bp-24
*   add     ax, word ptr [bx]        ; contains the segment of &num2
*   adc     dx, word ptr [bx+2]         ; not the contents of &num2
    add     ax, si                      ; add num3, which was
    adc     dx, si                      ; stored in si + di
    .
    .
    .

The function foo is called with &num3, &num2, and &num1, in that order.
The contents of num3 (300 in this case) are stored in the si and di
registers. The contents of num2 (200 in this case) are stored in bp-22
and bp-20. At the same time this is done, the segment of &num2 is stored
in bp-24. The contents of num1 (100 in this case) are stored in the ax,
dx register pair.

The problem occurs when an attempt is made to add num2. Even though
it was stored properly, the instructions generated to perform the
addition try to retrieve the value of num2 by using the segment stored
in bp-24 as an offset, rather then directly adding what was stored.
Replacing the three lines marked with an asterisk with these three
lines produces the correct result, as follows:

   mov     es, [bp-24]
   add     ax, es:[bp-22]
   adc     dx, es:[bp-20]

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.