As of FMSLogo 7.1.0, DLLCALL supports an "out buffer" parameter type creates a word that gets filled by the function being called. If the out buffer has zero bytes, then it creates an empty word that it doesn't act like the empty word. This is because parts of FMSLogo are written to assume there's exactly one empty word node but DLLCALL creates another word with a length of zero.
This is reproducible as far back as FMSLogo 7.1.0. Before that, DLLCALL didn't accept a "B" type for out parameters.
How Reproducible:
Every Time
Steps to Reproduce:
Run the following commands, one at a time:
DLLLOAD "kernel32.dll
MAKE "empty ITEM 2 DLLCALL [ L GetModuleFileNameW L 261 B 0 L 0 ]
SHOW COUNT :empty
SHOW WORD? :empty
SHOW EMPTY? :empty
SHOW FIRST :empty
SHOW BUTFIRST :empty
What Happens:
SHOW COUNT :empty prints0.
SHOW WORD? :empty prints true.
SHOW EMPTY? :empty prints false.
SHOW FIRST :empty prints a letter at random.
SHOW BUTFIRST :empty prints the blank line.
Expected Result:
SHOW COUNT :empty still prints0.
SHOW WORD? :empty still prints true.
Those were to illustrate that :empty is indeed an empty word.
SHOW EMPTY? :empty prints false.
SHOW FIRST :emptythrows a "doesn't like" error.
SHOW BUTFIRST :empty throws a "doesn't like" error.
Impact:
This is unlikely to impact users, as DLLCALL is a feature that very few people use and it doesn't make sense to use a buffer of zero bytes. That said, the impact is high for me because, after I did some cleanup in the implementation of first and butfirst, this causes a crash in the full test pass.
This is fixed by [r6219] and [r6220]. The fix will be available in FMSLogo 8.6.0.
I chose to fix this in DLLCALL, which was the simplest place to fix it.
Alternatively, I could have tried to find and remove any place in the code base which assumes that
Null_Wordis the only representation of the empty word. This would have been more invasive and would have undone whatever the original authors were trying to accomplish when they added Null_Word.I tried to add some prevention for this, but failed. My idea was to add an assert whenever a string node was used that, if it's length was 0, that it must be Null_Word. Two things made this hard. First, until the Null_Word is created, other string nodes may have zero length. Second, because Null_Word is interned, there are two NODEs with 0 length, the CASEOBJ that's interned and the empty word that it wraps.
Related
Commit: [r6219]
Commit: [r6220]
Last edit: David Costanzo 2026-05-25