[comp.lang.c] Is this a known TurboC bug?

pjh@tut.fi (Petri Haavisto) (10/26/88)

I have been using TurboC 1.5 for a large programming project and recently
found a bug in the switch-statement when the large memory model is used: In
some very unfortunate circumstances the program chooses the 'default'
action even if there is a suitable 'case'.

I have written a very simple demonstration program where the bug occurs.
The program asks for an integer value and switches according to that value.
If the user gives a value between 0 and 9 the program should write the text
"Some action was taken" on the screen. -100 is given to quit, and if
something else is input the program prints the text "Default action was
taken". Because of the bug the program chooses the 'default' even if a value
between 0 and 9 is given.

The source code looks extremely stupid because I have replaced all the
functions in the original program with calls to function do_nothing(). That
function is called with all sorts of parameters so do not use lint on the
program and do not suggest that it would be the cause of the problem.  The
original program made sense and I have just simplified this example as much
as possible. I have reduced the example program to a size where changing
almost anything makes the bug disappear. There is one unused local variable
and one unused function and a global structure that have to be there or
otherwise the bug once again disappears. They do not however have any
effect on what the program does.

The bug only comes out when large memory model is used. If the program is 
compiled via assembly using the -B option it works fine. Of course I
could always compile using the -B option but it is much slower and
unless I know the exact cause of the bug there is no way of knowing
that it couldn't happen there too. I have switched to another compiler
but I would still like to know:
1) Is this a previously known bug and what are the exact circumstances
where it comes out?
2) Is this bug corrected in v2.0?

/*----------compile: tcc -ml bug.c----------*/

struct {    /* just a structure that is later referred to */
    int         first_member;
    int         second_member[1];   /* array size could be something else */
} global_struct;

this_function_is_never_called(int some_flag)    /* but must be here */
{ 
    do_nothing(some_flag ? 1 : 0);
}

main() 
{
    int     c;
    char    *this_variable_is_not_used[1] = {""};

    for (;;) {
        /* First a series of calls to do_nothing-function. They have no 
           effect on the program but are necessary for the bug to come out. 
           All the parameters are simply ignored by do_nothing(). */
        do_nothing("", "", global_struct.first_member);
        do_nothing("", "", global_struct.first_member);
        do_nothing("", "", global_struct.first_member);
        do_nothing(global_struct.first_member);
        do_nothing(global_struct.second_member);
        do_nothing("", "", 0); do_nothing("", "", 0);
        do_nothing("", ""); do_nothing("", "");
        do_nothing("", ""); do_nothing("", ""); do_nothing("", "");
        
        /* Ask an integer value for the switch-statement */
        printf("write the value of c (-100 to quit): ");
        scanf("%d", &c);
        switch (c) {
            case 0: case 1: case 2: case 3: case 4:
            case 5: case 6: case 7: case 8: case 9: 
                printf("Some action was taken\n"); break;
            case -100: exit();
            default: 
                printf("Default action was taken. (c = %d)\n", c); break;
        }
    }
}

do_nothing() {}

/*----------program end----------*/

Petri Haavisto
Tampere University of Tecnology
Finland