Skip to content

Data.Int.toStringAs leaks a global n (missing local) #1

@Unisay

Description

@Unisay

Summary

src/Data/Int.lua declares the loop variable n in toStringAs without local, so it leaks into the global environment. luacheck --std min src/ flags it as setting non-standard global variable n, and because the rest of the function reads that name, the single missing local cascades into eight separate warnings.

Offending code

toStringAs = (function(radix)
  return function(i)
    local floor, insert = math.floor, table.insert
    n = floor(i)                       -- <-- no `local`: global leak
    if radix == 10 then return tostring(n) end
    ...
    if n < 0 then
      sign = "-"
      n = -n
    end
    repeat
      local d = (n % radix) + 1
      n = floor(n / radix)
      insert(t, 1, digits:sub(d, d))
    until n == 0
    ...

floor and insert on the preceding line are correctly local; only n was missed.

Root cause

A plain assignment n = floor(i) instead of local n = floor(i). In Lua an unqualified assignment to an undeclared name writes to the global table _G. Every later use of n in the function then resolves to that global rather than a local.

Impact

  • Functional: each call to Data.Int.toStringAs mutates the shared global n. In a single-threaded Lua program this is usually benign, but it is an unintended global write that can collide with any other code (the FFI runtime, user code, another module) that happens to use a global named n, producing hard-to-trace cross-module interference. It is the kind of latent footgun that only manifests under specific call interleavings.
  • Hygiene/tooling: luacheck --quiet --std min src/ exits non-zero on this file. The one missing local produces these warnings:
src/Data/Int.lua:25:7: setting non-standard global variable n
src/Data/Int.lua:26:43: accessing undefined variable n
src/Data/Int.lua:30:10: accessing undefined variable n
src/Data/Int.lua:32:9: setting non-standard global variable n
src/Data/Int.lua:32:14: accessing undefined variable n
src/Data/Int.lua:35:20: accessing undefined variable n
src/Data/Int.lua:36:9: setting non-standard global variable n
src/Data/Int.lua:36:19: accessing undefined variable n

All eight collapse once n is declared local.

How it was found

Linting the FFI sources of the Lua-fork package with luacheck --quiet --std min src/ while auditing the purescript-lua package ecosystem for Lua-5.1/global-hygiene issues.

Fix

Add local to the declaration of n:

local n = floor(i)

Minimal, single-line, src-only change. No behaviour change for any well-formed program; it merely confines n to the function scope where it belongs.

Note on out-of-scope warnings

The same file also reports accessing undefined field pow of global math (math.pow, removed in Lua 5.2+) and an unused argument nothing. Those are distinct pre-existing issues and are intentionally left out of this fix to keep the change minimal and focused on the global leak.

Cross-reference

Tracked upstream by pslua issue purescript-lua/purescript-lua#51; this is the detailed package-level report it points to.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions