Thread userdata shouldn't be overlooked - even though security contexts are
Roblox-specific, the thread userdata can still be used to implement a
permissions model for sandboxing, whether this is based on security contexts
(like Roblox, or like Ring 0/3), on capabilities, or maybe even something else.
I think it is worth it to document this in the sandboxing page.
For everyone's future reference:
* Every lua_State has an associated userdata pointer at the end. It's just a
pointer at the end called userdata:
void* userdata;
This pointer is never accessed or set by Luau itself, except for when
first initializing the state, where it is set to NULL.
This userdata can be set by the host after creating the thread, and is 100%
invisible to Luau code. C functions exposed by the host can access the
userdata by L->userdata, and, safe in the knowledge that it cannot be tampered
with, use it to validate the thread.
* The global_State (the VM, as opposed to just the main thread) contains a field
called cb:
lua_Callbacks cb;
The struct is currently defined as:
/* Callbacks that can be used to reconfigure behavior of the VM dynamically.
* These are shared between all coroutines.
*
* Note: interrupt is safe to set from an arbitrary thread but all other
* callbacks can only be changed when the VM is not running any code */
struct lua_Callbacks
{
/* gets called at safepoints (loop back edges, call/ret, gc) if set */
void (*interrupt)(lua_State* L, int gc);
/* gets called when an unprotected error is raised (if longjmp is
* used) */
void (*panic)(lua_State* L, int errcode);
/* gets called when L is created (LP == parent) or destroyed (LP ==
* NULL) */
void (*userthread)(lua_State* LP, lua_State* L);
/* gets called when a string is created; returned atom can be retrieved
* via tostringatom */
int16_t (*useratom)(const char* s, size_t l);
/* gets called when BREAK instruction is encountered */
void (*debugbreak)(lua_State* L, lua_Debug* ar);
/* gets called after each instruction in single step mode */
void (*debugstep)(lua_State* L, lua_Debug* ar);
/* gets called when thread execution is interrupted by break in another
* thread */
void (*debuginterrupt)(lua_State* L, lua_Debug* ar);
/* gets called when protected call results in an error */
void (*debugprotectederror)(lua_State* L);
};
Assuming you cache the global_State when creating the main thread (which you
should - it's just L->global), you can set g->cb->userthread to a C function
to define what should happen when a new thread is created or destroyed.
This can be used to:
* Inherit userdata from parent threads; great for permission models.
* Run destructors on userdata when threads are collected; great for resources.
That is a lot of information to digest, but if a Luau dev reads this, they'll
probably have said "yep, exactly" at least once. Documenting this small aspect
of the VM will be another step towards making it a bit friendlier for people to
start using Luau.
Obviously, the more technical documentation will remain here (in this commit &
pull request), but even the public facing documentation (which developers, like
me, will reference) should contain information just like the thread identity
section that was removed.
Hopefully, this is a suitable replacement, as thread userdata IS available in
the open-source version of Luau - and is used by Roblox for its "extra space" to
store things like thread identity.
As discussed in the issue, Luau has evolved from Lua to the point
where a new default extension `.luau` would be needed.
This change makes the REPL and Analyze look for `.luau`
extension first and if not found, fall back to `.lua`.
Right now our CMake infra specifies -Wno-unused only for GCC builds, but Makefile specifies it for all builds.
The intent has been to use it just for GCC, so we now do that by detecting the compiler version - this should
equalize the behavior across different types of builds.
Separately, latest version of clang appears to expose an unused variable that clang-10 was okay with, so fix that. (change from upstream)
- A series of major optimizations to type checking performance on complex
programs/types (up to two orders of magnitude speedup for programs
involving huge tagged unions)
- Fix a few issues encountered by UBSAN (and maybe fix s390x builds)
- Fix gcc-11 test builds
- Fix a rare corner case where luau_load wouldn't wake inactive threads
which could result in a use-after-free due to GC
- Fix CLI crash when error object that's not a string escapes to top level
- Fix Makefile suffixes on macOS
Co-authored-by: Rodactor <rodactor@roblox.com>
Changes:
- Support for time tracing for analysis/compiler (not currently exposed
through CLI)
- Support for type pack arguments in type aliases (#83)
- Basic support for require(path) in luau-analyze
- Add a lint warning for table.move with 0 index as part of
TableOperation lint
- Remove last STL dependency from Luau.VM
- Minor VS2022 performance tuning
Co-authored-by: Rodactor <rodactor@roblox.com>
When running `luau-analyze` with a .luarc that has a "mode" key, it outputs the following:
> .luaurc: Unknown key mode
I'm assuming it was named "mode" at first and was re-named "languageMode" later on?