lua-users home
lua-l archive

bug report: LUA compiler glitch

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi All,
please see the following example script.
Kind regards
 Lars Dölle
---8<--- snip -----8<---- snap -----
--[[
Summary:
 Lua version 5.1, 5.2beta and perhaps earlier contains what could
 be called a glitch in the compiler. It is very unlikely to cause
 troubles, thought, and can be worked around.
Diagnostic:
 Compiling assingment statements of the form
 var1[exp1],var2[exp2] = exp3,exp4
 should be translated to code executing serially
 |var1| |exp1| |var2| |exp2| |exp3| |exp4|
 SetTable @var1 @exp1 @exp3
 SetTable @var2 @exp2 @exp4
 but the assignment sequence in the end is inverted, meaning
 an execution sequence like
 |var1| |exp1| |var2| |exp2| |exp3| |exp4|
 SetTable @var2 @exp2 @exp4
 SetTable @var1 @exp1 @exp3
 is produced instead. The same holds for non-indexed variables,
 including locals, globals and upvalues.
Impact:
 All types of variables are effected by wrongly implemented
 semantics in rare, perhaps mechanically produced cases.
 While for globals, upvalues and locals the glitch could only
 be triggered by using the same variable twice in an assignment,
 a potential side effect on tables with __newindex might be
 provoked even using different variables.
 The semantics of the composite assignment is inconsistent.
Workaround:
 Decompose the assignment. The case of a vararg might be
 handled by first assigning to different locals.
Examples:
 follow
--]]
local function check(v,typ,name) -- utility
 io.write(string.format("%s '%s' is %d ",typ,name,v))
 if v == 1 then io.write(string.format("but should be 2")) end
 if v == 2 then io.write(string.format("as it should be")) end
 print()
end
-- demonstrating the glitch on locals --
local a
a,a = 1,2 -- 'a' is assigned 1 and not 2
check(a,"local ","a")
-- This behaviour is at least unexpected, since the assignment
-- intuitively should have the same meaning as
a = 1
a = 2
check(a,"local ","a")
-- identically, a local declaration properly yields 2
local a,a = 1,2
check(a,"local ","a")
-- likely, a functioncall yields 2
-- (needing ';()' since <function> is not a <prefixexp>)
;(function (a,a) check(a,"parm ","a") end)(1,2)
-- demonstrating the glitch on globals --
b,b = 1,2
check(b,"global","b")
-- demonstrating the glitch on closed upvalues --
;
(function ()
 local x
 return function ()
 x,x = 1,2
 check(x,"upval ","x")
 end
 end)()()
-- demonstrating the glitch on tables --
local x = {}
x.a,x.a = 1,2
check(x.a,"field ","a")
-- demonstrating the glitch on different variables --
local side_effect = 1
local function new(name,note)
 local instance = { name = name, note=note }
 setmetatable(instance,{ __newindex =
 function (_,idx,val)
 print("tbl",name, "idx",idx, "val",val, note,side_effect)
 side_effect = side_effect+1
 end })
 return instance
end
local A = new("A","side_effect should be 1st but is")
local B = new("B","side_effect should be 2nd but is")
A.a,B.b = 1,2

AltStyle によって変換されたページ (->オリジナル) /