Skip to content

Lua: a missing hashtable string is the null string - #1431

Closed
Frotty wants to merge 1 commit into
masterfrom
lua-absent-string-is-empty
Closed

Frotty wants to merge 1 commit into
masterfrom
lua-absent-string-is-empty

Conversation

@Frotty

@Frotty Frotty commented Oct 11, 2026

Copy link
Copy Markdown
Member

On Lua a missing hashtable string did not compare equal to null, as it does on Jass:

let h = InitHashtable()
if LoadStr(h, 1, 1) == null   // true on Jass and in the interpreter, false on Lua

On Lua, Wurst writes the null string as "": EliminateLocalTypes turns the null literal into "", and a native's nil guard answers "" for a string (LuaNativeLowering). The hashtable emulation was the exception. Both its in-place load and its __wurst_LoadStr helper answered nil for a missing string, so the comparison above became nil == "". A string passed on to a native was nil too. Only a concatenation was safe, because it guards a call's result with or "".

What changes

  • A string load answers "" when nothing is stored, both in place ((h.__wurst_ht_str[p] or __wurst_htEmpty)[c] or "") and in the helper. Handle loads still answer nil, which is the null handle.
  • LuaNativeLowering.neverNil knows that a string load of the emulation is never nil, so a concatenation of one adds no second or "". A concatenation prints the same as before.

A native declared without the BJ flag (an own @extern native LoadStr) still calls the game's native where the game has one; this changes only the emulation.

Tests

  • hashtableOperationsBehaveAsTheNatives (Jass, interpreter and Lua) and its optimised variant now also check LoadStr(...) == null under an absent parent key and an absent child key. anOperandWithAnEffectKeepsTheCallOfTheHelper checks the same through the helper. All three fail on master on Lua only.
  • hashtableOperationsArePrintedWhereTheyAreCalled checks the in-place shape and that a concatenation adds no guard of its own. hashtableLoadsUseTypeSpecificBuckets pinned the old nil and now pins "" for strings and nil for handles.
  • Passed: LuaHashtableTests, LuaNativesTests, LuaTranslationTests, LuaBackendAuditTests, StringByteSemanticsTests, CompiletimeHashtableTests. The full suite is left to CI. Not run in game.

On Lua the null string is "", but the hashtable emulation answered nil for a missing string, so LoadStr(h, p, c) == null was false where Jass says true. The in-place load and the helper answer "" now, and a concatenation of one adds no guard of its own.
@Frotty

Frotty commented Oct 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-11T08:02:52.234852Z 266497b Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 266497b8b2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Frotty

Frotty commented Oct 11, 2026

Copy link
Copy Markdown
Member Author

Closing. Measured on the 3.0.0 client, Jass keeps the null string and "" apart: null == "" is false, and a missing LoadStr equals null but not "". Making a missing string read as "" on Lua trades the == null mismatch for an == "" one. Matching Jass needs the null string to be nil on Lua, with nil-safe string natives where the game's Lua rejects nil (StringLength(nil) raises in the game, Jass answers 0). That is a separate change.

@Frotty Frotty closed this Oct 11, 2026
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.

1 participant