Luau `select` is returning wacky results (likely due to new flag!) (Causing Jailbreak to break upon join)

Reproduction Steps
No repro currently known, but happens 100% of time for SOME users, but seems related to recent FFlag, which maybe get rolled out slowly?

Expected Behavior
select(index, ...) when variadic only contains tables should only ever return a table. But for some reason I am getting a NUMBER returned, despite {...}[index] properly returning table.

Actual Behavior
As of a few hours ago we started getting reports of UI not loading when players join Jailbreak.

I was able to find a user to whom it was occurring, and it is happening 100% of the time they join. I discovered that an error was occurring in Roact, but it’s not Roact related – it’s in the Roact assign function which uses the select function. It is being passed completely normal, valid tables from a variadic such as…

local function f(source, ...)
  local index = 2
  print(select(index, ...))
end

But it is returning a NUMBER value. When I first assign to a table and index into it, it works fine… such as…

local t = {...}
local index = 2
print(t[index])

But interestingly enough, when I tried to isolate for a repro, it seemed to be working fine and not returning number. So I think something deeper in the Luau compiler may be happening here.

So, I took a look at recent FFlags, and noticed that one named LuauCompileSelectBuiltin which looks suspiciously exactly related to what I am experiencing.

So, despite not having a repro, I have reason to believe this flag is breaking Jailbreak at the moment. Happy to work with any engineer to find more info asap…

Issue Area: Engine
Issue Type: Other
Impact: Very High
Frequency: Constantly
Date First Experienced: 2022-02-01 00:02:00 (-05:00)

18 Likes

Thanks for the report! We’ve disabled the flag, and it should be off in new servers.

9 Likes

Thank you, I have received confirmation from affected users that it is resolved in new servers!

5 Likes

Thanks for raising this! We’ve been trying to figure it out for the last hour and finally tracked it to the select function. Came to raise it and saw someone beat us to it!

If it helps, it was only affecting mobile users.

Anyway, I can confirm it’s fixed in our testing!

Side note: It would be great to be able to raise bug tickets of our own one day

1 Like

Root cause: our new optimization for select() was missing a MOVE bytecode instruction on the fallback path in some cases; the said fallback path would always execute on older clients that don’t support the optimization, which would lead to the wrong first argument being passed to select. The numeric result is likely because the argument could have been '#' inherited from prior function calls. Our tests failed to catch this because the coverage for select in our conformance test suite was incomplete.

The fix for the problem as well as improved internal testing coverage will be available next week. We’ve disabled the optimization everywhere in the meantime. Sorry for the trouble!

23 Likes

In addition to mobile users, it was also affecting the W10 version. Not desktop, though.

1 Like

There seems to be a regression with this again, as of v0.513.0.5130420. One of my plugins uses select in a unique sort of way, and the result is that I’m getting an error where there wasn’t before.

An example reproduction:

local assets = {
	{id="Foo", size=32, theme=nil, content="foo"},
}

local keyFields = {"id", "size", "theme"}
local valueField = "content"

local function content(...)
	for _, asset in pairs(assets) do
		local okay = true
		for i, field in pairs(keyFields) do
			print("CHECK", asset[field], select(i, ...), asset[field] == select(i, ...))
			if asset[field] ~= select(i, ...) then
				okay = false
				break
			end
		end
		if okay then
			return asset[valueField]
		end
	end
	return nil
end

print(content("Foo", 32))
--> CHECK Foo Foo true
--> CHECK 32 32 true
--> CHECK nil function: 0x9a93ccc3d7b118c1 false    (!!!!)
--> nil                                             (should be "foo")

The gist is that, when select(3, a, b) is called, it’s returning some unexpected value instead of no value. The example above is returning some unknown function. The case with my plugin was returning some table. A more simplified test does not appear to reproduce this behavior.

Interestingly, and possibly a separate issue, printing with the select call as the last argument causes no value to be printed:

...
print(asset[field], select(i, ...))
...
--> CHECK Foo Foo 32
--> CHECK 32 32
--> CHECK nil            (????)
--> nil
2 Likes

Thanks for the repro! Will investigate.

4 Likes

Thanks for the report again! (We’ve disabled the flag)

This is an off-by-one error in the new fast path. You have two arguments here, and are trying to get the third one. Instead of correctly detecting this we returned the next value on the stack instead, which, due to Luau’s vararg layout, was the function being called (aka content).

The behavior in your second example is not affected by this optimization and is expected. select(3, ...) returns no values, not nil, so nothing is printed due to variadic expansion of calls in tail positions.

4 Likes

FWIW we’ve reenabled this in Studio just now; waiting for mobile upgrades to enable this in live games, but please let us know if there’s any further issues with this optimization (I hope not…).

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.