mirror of
https://github.com/fluffos/fluffos
synced 2026-08-12 18:26:06 -04:00
fix: ops.cc compound-assign efuns don't clear the lvalue's subtype
"undefined" (the value read back from a missing mapping key) is
represented as {T_NUMBER, subtype=T_UNDEFINED, 0}. The T_NUMBER cases
of &= /= %= *= |= ^= <<= >>= -= (src/packages/ops/ops.cc) modify the
lvalue's u.number in place via a compound C operator but never reset
its subtype, so a variable that started out undefined kept reporting
undefinedp() == 1 after a real arithmetic result had been computed
into it. f_xor_eq() didn't even clear the pushed result's subtype
either. The VM's own F_ADD_EQ (+=) already got this right for
comparison.
Also cleared f_or()'s result subtype to match its sibling f_and() --
same root cause (a plain `|` on an undefined left operand reused that
operand's stack slot, carrying its subtype into the real result).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YTPLudxra3u1andNyWJEQG
This commit is contained in:
parent
cdb1e9e923
commit
7a47120207
2 changed files with 73 additions and 0 deletions
|
|
@ -37,6 +37,7 @@ void f_and_eq() {
|
|||
error("Bad right type to &=\n");
|
||||
}
|
||||
sp->u.number = argp->u.number &= sp->u.number;
|
||||
argp->subtype = 0;
|
||||
sp->subtype = 0;
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ void f_div_eq() {
|
|||
} else {
|
||||
argp->u.number /= sp->u.number;
|
||||
}
|
||||
argp->subtype = 0;
|
||||
sp->u.number = argp->u.number;
|
||||
sp->subtype = 0;
|
||||
break;
|
||||
|
|
@ -380,6 +382,7 @@ void f_lsh_eq() {
|
|||
error("Illegal shift amount to <<=.\n");
|
||||
}
|
||||
sp->u.number = argp->u.number <<= sp->u.number;
|
||||
argp->subtype = 0;
|
||||
sp->subtype = 0;
|
||||
}
|
||||
|
||||
|
|
@ -400,6 +403,7 @@ void f_mod_eq() {
|
|||
} else {
|
||||
argp->u.number %= sp->u.number;
|
||||
}
|
||||
argp->subtype = 0;
|
||||
sp->u.number = argp->u.number;
|
||||
sp->subtype = 0;
|
||||
}
|
||||
|
|
@ -410,6 +414,7 @@ void f_mult_eq() {
|
|||
switch (argp->type | sp->type) {
|
||||
case T_NUMBER: {
|
||||
sp->u.number = argp->u.number *= sp->u.number;
|
||||
argp->subtype = 0;
|
||||
sp->subtype = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -554,6 +559,7 @@ void f_or() {
|
|||
CHECK_TYPES(sp, T_NUMBER, 2, F_OR);
|
||||
sp--;
|
||||
sp->u.number |= (sp + 1)->u.number;
|
||||
sp->subtype = 0;
|
||||
}
|
||||
|
||||
void f_or_eq() {
|
||||
|
|
@ -573,6 +579,7 @@ void f_or_eq() {
|
|||
error("Bad right type to |=\n");
|
||||
}
|
||||
sp->u.number = argp->u.number |= sp->u.number;
|
||||
argp->subtype = 0;
|
||||
sp->subtype = 0;
|
||||
}
|
||||
|
||||
|
|
@ -906,6 +913,7 @@ void f_rsh_eq() {
|
|||
error("Illegal shift amount to >>=.\n");
|
||||
}
|
||||
sp->u.number = argp->u.number >>= sp->u.number;
|
||||
argp->subtype = 0;
|
||||
sp->subtype = 0;
|
||||
}
|
||||
|
||||
|
|
@ -915,6 +923,7 @@ void f_sub_eq() {
|
|||
switch (argp->type | sp->type) {
|
||||
case T_NUMBER: {
|
||||
sp->u.number = argp->u.number -= sp->u.number;
|
||||
argp->subtype = 0;
|
||||
sp->subtype = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1213,6 +1222,8 @@ void f_xor_eq() {
|
|||
error("Bad right type to ^=\n");
|
||||
}
|
||||
sp->u.number = argp->u.number ^= sp->u.number;
|
||||
argp->subtype = 0;
|
||||
sp->subtype = 0;
|
||||
}
|
||||
|
||||
void f_function_constructor() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
// Compound-assign efuns (src/packages/ops/ops.cc) for &= /= %= *= |= ^=
|
||||
// <<= >>= -= modify an lvalue's u.number in place but used to leave its
|
||||
// subtype untouched. "undefined" (the value read back from a missing
|
||||
// mapping key) is represented as {T_NUMBER, subtype=T_UNDEFINED, 0} --
|
||||
// so a variable that started out undefined kept reporting undefinedp()
|
||||
// == 1 after a real arithmetic compound-assign computed a genuine
|
||||
// result. (Plain += already got this right, in the VM's F_ADD_EQ.)
|
||||
void do_tests() {
|
||||
mapping m = ([ "k": 0 ]);
|
||||
mixed u;
|
||||
|
||||
u = m["missing"];
|
||||
ASSERT_EQ(1, undefinedp(u));
|
||||
u &= 5;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(0, u);
|
||||
|
||||
u = m["missing"];
|
||||
u |= 5;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(5, u);
|
||||
|
||||
u = m["missing"];
|
||||
u ^= 5;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(5, u);
|
||||
|
||||
u = m["missing"];
|
||||
u -= 5;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(-5, u);
|
||||
|
||||
u = m["missing"];
|
||||
u *= 5;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(0, u);
|
||||
|
||||
u = m["missing"];
|
||||
u /= 5;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(0, u);
|
||||
|
||||
u = m["missing"];
|
||||
u %= 5;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(0, u);
|
||||
|
||||
u = m["missing"];
|
||||
u <<= 3;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(0, u);
|
||||
|
||||
u = m["missing"];
|
||||
u >>= 3;
|
||||
ASSERT_EQ(0, undefinedp(u));
|
||||
ASSERT_EQ(0, u);
|
||||
|
||||
// Plain (non-assign) `|` on an undefined operand must not carry the
|
||||
// "undefined" subtype into a real computed result either.
|
||||
u = m["missing"];
|
||||
ASSERT_EQ(0, undefinedp(u | 5));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue