[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: bug report: LUA compiler glitch
- From: Lars Doelle <lars.doelle@...>
- Date: Wed, 10 Aug 2011 00:22:27 +0200
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