tyfkda / xcc

Standalone C compiler/assembler/linker/libc for x86-64/aarch64/riscv64/wasm
https://tyfkda.github.io/xcc/
MIT License
198 stars 14 forks source link

division issues #107

Closed ghost closed 1 year ago

ghost commented 1 year ago

I’m not sure if this should be split into multiple reports (because I’m not sure what the underlying causes are), but I found a few issues with how the compiler handles divisions.

The original issue I ran into was that I had the following code in on one of my programs

// do not assume 'char' is eight bits
some_unsigned_char %= 0x100;

It is meant to be a portable program, so I don’t want to assume CHAR_BIT is eight. I have that modulo set up so that the some_char variable is bounded to the range 0..255 on implementations where CHAR_BIT > 8. On implementations where CHAR_BIT is indeed just eight, that line is meant to be a noop.

But compiling it to Wasm with wcc, I found that it converts it to a division by zero, which causes the program to crash at runtime.

Trying to come up with a simple reproduction case, and testing it on xcc, I found that a program such as this causes the compiler itself to crash.

int main(void)
{
    int i = 1;
    i /= 0;
    return 0;
}

And likewise for the following program (which should definitely be valid, I’m pretty sure).

int main(void)
{
    unsigned char i = 1;
    i /= 0x100;
    return 0;
}

Under xcc, programs involving %= on char and unsigned char seem to fail during assembly.

*stdin*(14): Illegal register
        mov %ah, %r10b
*stdin*(14): Syntax error
        mov %ah, %r10b
*stdin*(14): Illegal opeand
        mov %ah, %r10b
tyfkda commented 1 year ago

Hi @zamfofex , thank you for reporting the problem.

It looks several issues are exist in compiler. I'll look into it.

tyfkda commented 1 year ago

@zamfofex I've pushed main branch, and hope these problems are solved. Would you please try it again? Thanks!

ghost commented 1 year ago

Hello! Thank you for looking into this. I have tried out your changes, and it worked mostly well, except that I found one problem with them. A division by zero on a non‐static initializer should not prevent the program from compiling successfully.

int main(void)
{
   int i = 1 / 0;
   return 0;
}

Now, granted, the program above is silly, because it’ll always cause undefined behavior, but if the int i = 1 / 0; declaration were in a branch that is never executed, it is possible for a program to contain such a construct and not cause undefined behavior at all during runtime.

Since division by zero is undefined behavior at runtime, what you do here doesn’t really matter. You can just convert any compile‐time divisions by zero to 0 itself, for example. (Rather than emitting an actual division, which might be more difficult to set up.)

But also note that the following programs should fail to compile (and currently do indeed fail) because the division by zero is performed on a static initializer:

int main(void)
{
   static int i = 1 / 0;
   return 0;
}
int xxx = 1 / 0;
int main(void)
{
   return 0;
}
tyfkda commented 1 year ago

@zamfofex I see, but I think it is not a big problem. Do you mind me closing this issue?

ghost commented 1 year ago

You don’t have to ask me before closing the issue! :sweat_smile: If you don’t think the issue is worthwhile fixing, you can close it, and that’s fine. But I could try to tackle fixing it by myself, if you feel like you’d accept a pull request.