luax icon indicating copy to clipboard operation
luax copied to clipboard

Attempt to index a number value (local 'p')

Open stag-enterprises opened this issue 1 year ago • 2 comments

I've been using LuaX, and I seem to have encountered an issue with the standard library. I don't anything wrong with my function. Using normal Lua, as you can see here on TIO, executes the function perfectly fine. This is LuaX via ypp, if that helps things.

Error trace:

$luax:libluax/fs/fs.lua:48: error: attempt to index a number value (local 'p')

/home/stag/ghq/github.com/stag-enterprises/assets/mod.lua:24:
  19 |  end
  20 |
  21 |  function format_mode(mode)
  22 |          local str = ""
  23 |          for i = 8, 0, -1 do
  24 =>                 local bit = math.floor(mode / 2 ^ i) % 2 == 1
  25 |                  if i % 3 == 2 then
  26 |                          str = str .. (bit and "r" or "-")
  27 |                  elseif i % 3 == 1 then
  28 |                          str = str .. (bit and "w" or "-")
  29 |                  else

/home/stag/ghq/github.com/stag-enterprises/assets/mod.lua:43:
  38 |  data.context = "/" .. data.context .. "/"
  39 |
  40 |  for i = 1, #data.dirs do
  41 |          data.dirs[i].modified = os.date("%Y-%m-%d %H:%M:%S", data.dirs[i].modified)
  42 |          data.dirs[i].accessed = os.date("%Y-%m-%d %H:%M:%S", data.dirs[i].accessed)
  43 =>         data.dirs[i].mode = format_mode(data.dirs[i].mode)
  44 |  end
  45 |
  46 |  for i = 1, #data.files do
  47 |          data.files[i].modified = os.date("%Y-%m-%d %H:%M:%S", data.files[i].modified)
  48 |          data.files[i].accessed = os.date("%Y-%m-%d %H:%M:%S", data.files[i].accessed)

[string "..."]:2:
   1 |
   2 => mod = require "mod"
   3 |  each, data = mod.each, mod.data

The offending function:

function format_mode(mode)
        local str = ""
        for i = 8, 0, -1 do
                local bit = math.floor(mode / 2 ^ i) % 2 == 1
                if i % 3 == 2 then
                        str = str .. (bit and "r" or "-")
                elseif i % 3 == 1 then
                        str = str .. (bit and "w" or "-")
                else
                        str = str .. (bit and "x" or "-")
                end
        end
        return str
end

stag-enterprises avatar Mar 06 '25 06:03 stag-enterprises

LuaX redefines the / operator to build path, using the right path separator according to the OS (/ or \\).

I guess your function receives a string (containing a number) instead of a number and fs.join can not make a path with mode and 2^i since the second argument is not a string.

In this case, an explicit conversion should help (mode = tonumber(mode)).

When I wrote this operator (which is clearly not a division) I made the assumption that arithmetic operators are not used on strings (which is obviously not the case).

I would suggest not to use arithmetic operations on string since not all of them will convert string to numbers (+, / will, <, <= won't, e.g. "1" > "010" is true and "1"+0 > "010"+0 is false !)

CDSoft avatar Mar 06 '25 07:03 CDSoft

Your code assumes mode is in base 8, so the fix is mode = tonumber(mode, 8).

If you can use bit operations, you ca also simplify your function. E.g.:

function format_mode(mode)
    mode = tonumber(mode, 8)
    local m = {[2]="r", [1]="w", [0]="x"}
    local str = ""
    for i = 0, 8 do
        str = (mode&(1<<i) ~= 0 and m[i%3] or "-") .. str
    end
    return str
end

print(format_mode("755")) -- prints "rwxr-xr-x"

CDSoft avatar Mar 06 '25 07:03 CDSoft