Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible overflow issue on expressions. #101

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

Krush206
Copy link

@Krush206 Krush206 commented May 2, 2024

I noticed putn1 breaks the conversion if the last bit is set.

On my machine (an ARM-based cellphone)

@ calc = ( 1 << 63 )

raises a @: Badly formed number. error. I inspected why's that, and turns out the conversion yields a ( (left parenthesis) character.

I can tell the program isn't careful on overflow, since none of the variables and functions are typed unsigned, and there doesn't seem to exist any validity checks on overflow.

Typing putn1's argument as unsigned remedied the issue.

I'm not sure if my solution is portable, but is what made the fix. I also provide portability among different character encodings.

Lastly, line 193 on sh.exp.c has a wrong type. On my machine

@ ret = ( 0 || 1 << 32 )

yields 0.

@zoulasc
Copy link
Member

zoulasc commented May 3, 2024

Well you are just making the number unsigned which means that now negative expressions don't work anymore, with the tradeoff of doubling the positive number range... I don't think this is a useful change (negative expressions are more popular). It would be better to detect and fix:
[DING!] 201>@ x = (1 << 65 )
[1:00pm] 202>echo $x
2

:-)

@Krush206
Copy link
Author

Krush206 commented May 3, 2024

Maybe I wasn't clear. The concern isn't actually on overflow, but on that signed overflow is undefined behavior. According to this page, the standard states unsigned overflow wraps around, and is portable, unless strong optimizations are set.

However, I'm afraid the operation

if (n & ~(~(unsigned tcsh_number_t) 0 >> 1))

isn't portable, since it's bitwise. I'm (very likely wrongly) assuming the last bit is the sign bit on every machine. I don't know what the standard states on bitwise operations and sign bit.

I had a problem with relational operators, but

switch ((int) i) {
    tcsh_number_t is;

case GTR:
    if ((i = egetn(p1)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        is = -(tcsh_number_t) -i;
    else
        is = i;
    if ((i = egetn(p2)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        i = is > -(tcsh_number_t) -i;
    else
        i = is > (tcsh_number_t) i;
    break;

case GTR | 1:
    if ((i = egetn(p1)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        is = -(tcsh_number_t) -i;
    else
        is = i;
    if ((i = egetn(p2)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        i = is >= -(tcsh_number_t) -i;
    else
        i = is >= (tcsh_number_t) i;
    break;

case LSS:
    if ((i = egetn(p1)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        is = -(tcsh_number_t) -i;
    else
        is = i;
    if ((i = egetn(p2)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        i = is < -(tcsh_number_t) -i;
    else
        i = is < (tcsh_number_t) i;
    break;

case LSS | 1:
    if ((i = egetn(p1)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        is = -(tcsh_number_t) -i;
    else
        is = i;
    if ((i = egetn(p2)) &
~(~(unsigned tcsh_number_t) 0 >> 1))
        i = is <= -(tcsh_number_t) -i;
    else
        i = is <= (tcsh_number_t) i;
    break;
}

made the fix. Note I cast operands that can be represented in signed quantity on comparison because, from what I've read, the standard states comparison between signed and unsigned, before the comparison, the signed operand is converted to unsigned. I had problems without a cast.

Negative expressions are working fine for me, though I've tested only on one machine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants