duskos

dusk os fork
git clone git://git.alexwennerberg.com/duskos
Log | Files | Refs | README | LICENSE

commit b1968b19c4d94c75649409191792e8dbd161969d
parent db256f2dfad6de68510b228c97cefd798cf80df2
Author: Virgil Dupras <hsoft@hardcoded.net>
Date:   Sat, 17 Dec 2022 12:04:25 -0500

comp/c: fix submarine bug with "typeunsigned?"

the word "typeunsigned?" assumed a simple type but was used in cases where it
was possible to have a CType. This was broken since forever, but because so far
didn't cause problems, by chance. With the introduction of "uchar" "ushort" and
"uint" typedefs, we added a level of type indirection that wasn't there before
and activated the bug, which is *very* tricky to debug because the result of a
buggy "typeunsigned?" depends on the type's place in memory.

I've been tracking this bug for 2 days, thinking it was some really deep memory
corruption bug. Nope, just a stupid bug.

The test added in this commit doesn't fail with the unamended code... by chance.
If you do something like add a "?f<< /comp/c/pp.fs" line at the top of
/tests/all.fs, then you'll get the fail, under i386 only, which is fixed by this
commit.

Diffstat:
Mfs/comp/c/pp.fs | 1+
Mfs/comp/c/type.fs | 7++++---
Mfs/tests/comp/c/cc.fs | 2++
Mfs/tests/comp/c/test.c | 6++++++
4 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/fs/comp/c/pp.fs b/fs/comp/c/pp.fs @@ -8,6 +8,7 @@ \ then processed regularly until the end of string, at which point we go back to \ our previous feed. This system works recursively. \ Macro are stored as null-terminated ranges, *not* regular strings. +?f<< /lib/str.fs ?f<< /lib/arena.fs ?f<< /comp/c/feed.fs diff --git a/fs/comp/c/type.fs b/fs/comp/c/type.fs @@ -58,9 +58,6 @@ STORAGE_MEM value curstorage : _arena curstorage STORAGE_MEM <> curstatic or if _tarena else _parena then ; 4 stringlist typenames "void" "char" "short" "int" -: typeunsigned? ( type -- flags ) 4 rshift 1 and ; -: typesigned! ( type -- type ) $f and ; -: typeunsigned! ( type -- type ) $10 or ; : type*lvl ( type -- lvl ) 3 and ; \ TODO: have the _assert in type*lvl! it's not possible now because it breaks \ the CC vms. @@ -148,6 +145,10 @@ struct[ CType : :append ( other self -- ) 2dup :size swap to offset llappend ; ]struct +: ensurebasetype ( type -- type ) + dup ctype? if ctype' CType type ensurebasetype then ; +: typeunsigned? ( type -- flags ) ensurebasetype 4 rshift 1 and ; + \ Typedefs are dictionary entries in the "typedefs" dicts, which contain a 4b \ value representing the type it aliases. create typedefs 0 , 0 c, \ this is a dict link diff --git a/fs/tests/comp/c/cc.fs b/fs/tests/comp/c/cc.fs @@ -89,6 +89,8 @@ binop9 $1234 #eq $72 2 binop11 $1c #eq 12 5 binop12 17 #eq scnt not # 54 5 binop12 -1 #eq scnt not # +1 42 binop13 1 #eq +-1 42 binop13 0 #eq structop1 44 #eq structop2 45 #eq structop3 42 #eq diff --git a/fs/tests/comp/c/test.c b/fs/tests/comp/c/test.c @@ -360,6 +360,12 @@ char binop11(char a, char b) { int binop12(int a, int b) { return a < 42 ? adder(a, b) : -1 ; } +// This one fixes a bug where "typeunsigned?" didn't account for the possibility +// of getting a CType in parameter. But this test doesn't reliably fail. It +// depends on where in memory the CType is placed. +int binop13(ushort a, ushort b) { + return a < b; +} short structop1() { globdata.bar += 2; return globdata.bar;