As requested by Christian here is a code-sample to replicate the bug
This borrows heavily from libtcc_test.c, so if you are able to run that you can 
run this, which requires passing in the path to where tcclib.h and libtcc1.a 
lies via a -B option, for example:  -Bc:/git/tcc/win32).

With out the fix the program prints:  1000 > 2000 : true
With this fix described below the program prints:  1000 > 2000 : false

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "libtcc.h"

bool greater(int a, int b)
{
       return a > b;
}

char my_program[] =
"#include <tcclib.h>\n"
"#include <stdbool.h>\n\n"
"extern bool greater(int a, int b);\n\n"
"void foo(void)\n"
"{\n"
"    printf(\"%d > %d : %s\", 1000, 2000, greater(1000,2000) ? \"true\" : 
\"false\");\n"
"}\n";

int main(int argc, char **argv)
{
    TCCState *s;
    int i;
    void (*func)(void);

    s = tcc_new();
    if (!s) {
        fprintf(stderr, "Could not create tcc state\n");
        exit(1);
    }

    /* if tcclib.h and libtcc1.a are not installed, where can we find them */
    for (i = 1; i < argc; ++i) {
        char *a = argv[i];
        if (a[0] == '-') {
            if (a[1] == 'B')
                tcc_set_lib_path(s, a+2);
            else if (a[1] == 'I')
                tcc_add_include_path(s, a+2);
            else if (a[1] == 'L')
                tcc_add_library_path(s, a+2);
        }
    }

    tcc_set_output_type(s, TCC_OUTPUT_MEMORY);

    if (tcc_compile_string(s, my_program) == -1)
        return 1;

              tcc_add_symbol(s, "greater", greater);

    if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0)
        return 1;

    func = tcc_get_symbol(s, "foo");
    if (!func)
        return 1;

    func();

    tcc_delete(s);

    return 0;
}



From: Louis Botha
Sent: Sunday, February 3, 2019 4:54 PM
To: '[email protected]' <[email protected]>
Subject: Bug in _Bool return values

Hi TCC-fans,

Think I found a bug in the implementation of _Bool in return values in version 
0.9.27, found on i386, probably applies to x86_64, and possibly others as well:
Since sizeof(_Bool) == 1 as implemented in TCC, I believe this comment in 
i386-gen.c applies:
"extend the return value to the whole register if necessary
visual studio and gcc do not always set the whole eax register
when assigning the return value of a function"

The scenario that broke for me was calling a function that only set the AL 
register on return, leaving the rest of EAX undefined, yet TCC checked the 
whole of EAX for the _Bool return value (true came out correct, but false 
tested as true when the undefined-bits were non-0)

Assigning the _Bool return value to a _Bool variable and then checking that 
variable instead of the return value is one confirmed workaround (the emitted 
TCC code then uses just AL to generate a full EAX before checking EAX), but I 
think I have found the proper fix:

Add "case VT_BOOL:" as shown here, just after line 365 of i386-gen.c:

switch (rt & VT_BTYPE) {
    case VT_BYTE:
    case VT_BOOL:

This modification fixed the problem I was having, I *think* the line in 
x86_64-gen.c that needs to change for the equivalent there is this (@ line 934):

else if (bt == VT_BYTE || bt == VT_BOOL)

Sorry, I don't know the other architectures or TCC in general well enough to 
comment on other places that may also need this fix.

Best regards,
Louis

_______________________________________________
Tinycc-devel mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

Reply via email to