Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generated byte code uses incorrect table object when indexing the result of a function #24

Open
Adrodoc opened this issue Apr 29, 2019 · 1 comment

Comments

@Adrodoc
Copy link

Adrodoc commented Apr 29, 2019

The following Lua code

main.lua

t = {}
function f()
return t
end
f().a=true
print(t.a)

is supposed to print true (Confirmed with https://www.lua.org/cgi-bin/demo).

Instead it fails with:

Exception in thread "main" net.sandius.rembulan.exec.CallException: net.sandius.rembulan.runtime.IllegalOperationAttemptException: attempt to index a boolean value
	at net.sandius.rembulan.exec.DirectCallExecutor$Result.get(DirectCallExecutor.java:184)
	at net.sandius.rembulan.exec.DirectCallExecutor.execute(DirectCallExecutor.java:310)
	at net.sandius.rembulan.exec.DirectCallExecutor.resume(DirectCallExecutor.java:252)
	at net.sandius.rembulan.exec.DirectCallExecutor.call(DirectCallExecutor.java:228)
	at net.wizardsoflua.rembulan.bug.RembulanBugMain.main(RembulanBugMain.java:30)
Caused by: net.sandius.rembulan.runtime.IllegalOperationAttemptException: attempt to index a boolean value
	at net.sandius.rembulan.runtime.Errors.illegalIndexAttempt(Errors.java:70)
	at net.sandius.rembulan.runtime.Dispatch.setindex(Dispatch.java:1533)
	at ByteCode0.run(main.lua:5)
	at ByteCode0.invoke(main.lua)
	at net.sandius.rembulan.runtime.AbstractFunction0.invoke(AbstractFunction0.java:51)
	at net.sandius.rembulan.runtime.Dispatch.mt_invoke(Dispatch.java:95)
	at net.sandius.rembulan.runtime.Dispatch.call(Dispatch.java:402)
	at net.sandius.rembulan.runtime.Coroutine$BootstrapResumable.resume(Coroutine.java:90)
	at net.sandius.rembulan.runtime.ResumeInfo.resume(ResumeInfo.java:36)
	at net.sandius.rembulan.runtime.Call$Resumer.continueCurrentCoroutine(Call.java:513)
	at net.sandius.rembulan.runtime.Call$Resumer.resume(Call.java:537)
	at net.sandius.rembulan.runtime.Call.resume(Call.java:232)
	at net.sandius.rembulan.runtime.Call.access$000(Call.java:37)
	at net.sandius.rembulan.runtime.Call$CallContinuation.resume(Call.java:181)
	at net.sandius.rembulan.exec.DirectCallExecutor.execute(DirectCallExecutor.java:290)
	... 3 more

It looks like the boolean value and table t get swapped when passing them to net.sandius.rembulan.runtime.Dispatch.setindex(ExecutionContext, Object, Object, Object) from the generate byte code. With a breakboint in Dispatch.setindex you can clearly see this.

Complete example:

package net.wizardsoflua.rembulan.bug;

import net.sandius.rembulan.StateContext;
import net.sandius.rembulan.Table;
import net.sandius.rembulan.Variable;
import net.sandius.rembulan.compiler.CompilerChunkLoader;
import net.sandius.rembulan.env.RuntimeEnvironment;
import net.sandius.rembulan.env.RuntimeEnvironments;
import net.sandius.rembulan.exec.DirectCallExecutor;
import net.sandius.rembulan.impl.StateContexts;
import net.sandius.rembulan.lib.BasicLib;
import net.sandius.rembulan.runtime.LuaFunction;

public class RembulanBugMain {
  public static void main(String[] args) throws Exception {
    StateContext stateContext = StateContexts.newDefaultInstance();
    Table env = stateContext.newTable();
    CompilerChunkLoader loader = CompilerChunkLoader.of("ByteCode");
    RuntimeEnvironment runtimeEnvironment = RuntimeEnvironments.system();
    BasicLib.installInto(stateContext, env, runtimeEnvironment, loader);
    Variable envVariable = new Variable(env);
    LuaFunction mainFunction = loader.loadTextChunk(envVariable, "main.lua", "t = {}\n" + //
        "function f()\n" + //
        "return t\n" + //
        "end\n" + //
        "f().a=true\n" + //
        "print(t.a)\n" //
    );
    DirectCallExecutor newExecutor = DirectCallExecutor.newExecutor();
    newExecutor.call(stateContext, mainFunction);
  }
}
@Adrodoc
Copy link
Author

Adrodoc commented Apr 29, 2019

The issue is caused by IRTranslatorTransformer.popVal() prefering to pop Vals over MultiVals.

In this example IRTranslatorTransformer.transform(IndexExpr) calls IRTranslatorTransformer.transform(FunctionCallExpr) in line 215 expecting the latter to push a Val or MultiVal, so that it can be popped in line 216.
Beeing a funtion call the latter pushes a MultiVal.
Normally this would not be a problem, because IRTranslatorTransformer.popVal() can handle both Val and MultiVal, but the caller of IRTranslatorTransformer.transform(IndexExpr) which is IRTranslatorTransformer.transform(AssignStatement) previously pushed the value-Val which contains the boolean used in the assignment and is supposed to be popped in line 225.
Because IRTranslatorTransformer.popVal() prefers popping Vals over MultiVals the boolean value-Val overtakes the MultiVal which causes table and value to get swapped.

There are two ways to resolve this issue:

  1. Keep the order across Vals and MultiVals in IRTranslatorTransformer.popVal().
  2. Pop the value-Val in IRTranslatorTransformer.transform(IndexExpr) before visiting e.object().

Adrodoc added a commit to wizards-of-lua/rembulan that referenced this issue Apr 30, 2019
…n indexing the result of a function (second proposed solution)
Adrodoc added a commit to wizards-of-lua/rembulan that referenced this issue Apr 30, 2019
Fix mjanicek#24 - Generated byte code uses incorrect table object when indexing the result of a function
luavixen pushed a commit to luavixen/rembulan that referenced this issue Aug 29, 2022
…n indexing the result of a function (second proposed solution)
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

No branches or pull requests

1 participant