From a80fc936469efc557847796efefa72107dc10d6b Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Fri, 5 Nov 2021 12:39:27 -0700 Subject: [PATCH 1/6] Fix unused variable treatment (#139) 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) --- Ast/src/Parser.cpp | 5 ----- Makefile | 5 ++++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/Ast/src/Parser.cpp b/Ast/src/Parser.cpp index 846bc0ba..ee84542d 100644 --- a/Ast/src/Parser.cpp +++ b/Ast/src/Parser.cpp @@ -2379,15 +2379,12 @@ AstArray Parser::parseTypeParams() Lexeme begin = lexer.current(); nextLexeme(); - bool seenPack = false; while (true) { if (FFlag::LuauParseTypePackTypeParameters) { if (shouldParseTypePackAnnotation(lexer)) { - seenPack = true; - auto typePack = parseTypePackAnnotation(); if (FFlag::LuauTypeAliasPacks) // Type packs are recorded only is we can handle them @@ -2399,8 +2396,6 @@ AstArray Parser::parseTypeParams() if (typePack) { - seenPack = true; - if (FFlag::LuauTypeAliasPacks) // Type packs are recorded only is we can handle them parameters.push_back({{}, typePack}); } diff --git a/Makefile b/Makefile index ea416be4..e96a9cbd 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,10 @@ OBJECTS=$(AST_OBJECTS) $(COMPILER_OBJECTS) $(ANALYSIS_OBJECTS) $(VM_OBJECTS) $(T CXXFLAGS=-g -Wall -Werror LDFLAGS= -CXXFLAGS+=-Wno-unused # temporary, for older gcc versions +# temporary, for older gcc versions as they treat var in `if (type var = val)` as unused +ifeq ($(findstring g++,$(shell $(CXX) --version)),g++) + CXXFLAGS+=-Wno-unused +endif # configuration-specific flags ifeq ($(config),release) From ad9b47b72fb664c518a8e55471c58a3e21986cd0 Mon Sep 17 00:00:00 2001 From: bmcq-0 <66541602+bmcq-0@users.noreply.github.com> Date: Fri, 5 Nov 2021 16:24:30 -0400 Subject: [PATCH 2/6] Fold length operations when argument is a constant string (#141) Co-authored-by: Arseny Kapoulkine --- Compiler/src/Compiler.cpp | 5 +++++ tests/Compiler.test.cpp | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp index 7750a1d9..4c86b6f9 100644 --- a/Compiler/src/Compiler.cpp +++ b/Compiler/src/Compiler.cpp @@ -2900,6 +2900,11 @@ struct Compiler break; case AstExprUnary::Len: + if (arg.type == Constant::Type_String) + { + result.type = Constant::Type_Number; + result.valueNumber = double(arg.valueString.size); + } break; default: diff --git a/tests/Compiler.test.cpp b/tests/Compiler.test.cpp index bbac3302..1389bfec 100644 --- a/tests/Compiler.test.cpp +++ b/tests/Compiler.test.cpp @@ -1168,6 +1168,17 @@ RETURN R0 1 )"); } +TEST_CASE("ConstantFoldStringLen") +{ + CHECK_EQ("\n" + compileFunction0("return #'string', #'', #'a', #('b')"), R"( +LOADN R0 6 +LOADN R1 0 +LOADN R2 1 +LOADN R3 1 +RETURN R0 4 +)"); +} + TEST_CASE("ConstantFoldCompare") { // ordered comparisons From 6342913533b26045a6a254519e88aff6359026a5 Mon Sep 17 00:00:00 2001 From: Rerumu <25379555+Rerumu@users.noreply.github.com> Date: Fri, 5 Nov 2021 17:38:08 -0400 Subject: [PATCH 3/6] Fix small assert ordering (#143) --- Compiler/src/Compiler.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp index 4c86b6f9..45d10cc3 100644 --- a/Compiler/src/Compiler.cpp +++ b/Compiler/src/Compiler.cpp @@ -2465,9 +2465,10 @@ struct Compiler } else if (node->is()) { + LUAU_ASSERT(!loops.empty()); + // before exiting out of the loop, we need to close all local variables that were captured in closures since loop start // normally they are closed by the enclosing blocks, including the loop block, but we're skipping that here - LUAU_ASSERT(!loops.empty()); closeLocals(loops.back().localOffset); size_t label = bytecode.emitLabel(); @@ -2478,12 +2479,13 @@ struct Compiler } else if (AstStatContinue* stat = node->as()) { + LUAU_ASSERT(!loops.empty()); + if (loops.back().untilCondition) validateContinueUntil(stat, loops.back().untilCondition); // before continuing, we need to close all local variables that were captured in closures since loop start // normally they are closed by the enclosing blocks, including the loop block, but we're skipping that here - LUAU_ASSERT(!loops.empty()); closeLocals(loops.back().localOffset); size_t label = bytecode.emitLabel(); From 1e1d1f58e9bb9b196ec983a0d4bde605d6fbdd0f Mon Sep 17 00:00:00 2001 From: "Roni N. (Kittenz)" Date: Sat, 6 Nov 2021 04:11:26 +0200 Subject: [PATCH 4/6] Look for `.luau` before `.lua` in REPL & Analyze (#97) (#124) 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`. --- CLI/Analyze.cpp | 18 ++++++++++++++---- CLI/Repl.cpp | 10 ++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CLI/Analyze.cpp b/CLI/Analyze.cpp index ed0552d7..d72a865d 100644 --- a/CLI/Analyze.cpp +++ b/CLI/Analyze.cpp @@ -115,7 +115,12 @@ struct CliFileResolver : Luau::FileResolver { if (Luau::AstExprConstantString* expr = node->as()) { - Luau::ModuleName name = std::string(expr->value.data, expr->value.size) + ".lua"; + Luau::ModuleName name = std::string(expr->value.data, expr->value.size) + ".luau"; + if (!moduleExists(name)) + { + // fall back to .lua if a module with .luau doesn't exist + name = std::string(expr->value.data, expr->value.size) + ".lua"; + } return {{name}}; } @@ -236,8 +241,15 @@ int main(int argc, char** argv) if (isDirectory(argv[i])) { traverseDirectory(argv[i], [&](const std::string& name) { - if (name.length() > 4 && name.rfind(".lua") == name.length() - 4) + // Look for .luau first and if absent, fall back to .lua + if (name.length() > 5 && name.rfind(".luau") == name.length() - 5) + { failed += !analyzeFile(frontend, name.c_str(), format, annotate); + } + else if (name.length() > 4 && name.rfind(".lua") == name.length() - 4) + { + failed += !analyzeFile(frontend, name.c_str(), format, annotate); + } }); } else @@ -256,5 +268,3 @@ int main(int argc, char** argv) return (format == ReportFormat::Luacheck) ? 0 : failed; } - - diff --git a/CLI/Repl.cpp b/CLI/Repl.cpp index 4968d080..323ab144 100644 --- a/CLI/Repl.cpp +++ b/CLI/Repl.cpp @@ -51,9 +51,13 @@ static int lua_require(lua_State* L) return finishrequire(L); lua_pop(L, 1); - std::optional source = readFile(name + ".lua"); + std::optional source = readFile(name + ".luau"); if (!source) - luaL_argerrorL(L, 1, ("error loading " + name).c_str()); + { + source = readFile(name + ".lua"); // try .lua if .luau doesn't exist + if (!source) + luaL_argerrorL(L, 1, ("error loading " + name).c_str()); // if neither .luau nor .lua exist, we have an error + } // module needs to run in a new thread, isolated from the rest lua_State* GL = lua_mainthread(L); @@ -511,5 +515,3 @@ int main(int argc, char** argv) return failed; } } - - From 96b1707f8778921465d62e5dcaf5d79432a07707 Mon Sep 17 00:00:00 2001 From: Rerumu <25379555+Rerumu@users.noreply.github.com> Date: Fri, 5 Nov 2021 22:11:56 -0400 Subject: [PATCH 5/6] Fix CLI analysis reporting wrong file names (#146) --- CLI/Analyze.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/CLI/Analyze.cpp b/CLI/Analyze.cpp index d72a865d..798ead06 100644 --- a/CLI/Analyze.cpp +++ b/CLI/Analyze.cpp @@ -34,8 +34,10 @@ static void report(ReportFormat format, const char* name, const Luau::Location& } } -static void reportError(ReportFormat format, const char* name, const Luau::TypeError& error) +static void reportError(ReportFormat format, const Luau::TypeError& error) { + const char* name = error.moduleName.c_str(); + if (const Luau::SyntaxError* syntaxError = Luau::get_if(&error.data)) report(format, name, error.location, "SyntaxError", syntaxError->message.c_str()); else @@ -49,7 +51,10 @@ static void reportWarning(ReportFormat format, const char* name, const Luau::Lin static bool analyzeFile(Luau::Frontend& frontend, const char* name, ReportFormat format, bool annotate) { - Luau::CheckResult cr = frontend.check(name); + Luau::CheckResult cr; + + if (frontend.isDirty(name)) + cr = frontend.check(name); if (!frontend.getSourceModule(name)) { @@ -58,7 +63,7 @@ static bool analyzeFile(Luau::Frontend& frontend, const char* name, ReportFormat } for (auto& error : cr.errors) - reportError(format, name, error); + reportError(format, error); Luau::LintResult lr = frontend.lint(name); From c6de3bd2e4b6a9e892d5690b393631cc33ef60b3 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Fri, 5 Nov 2021 19:50:29 -0700 Subject: [PATCH 6/6] Update sandbox.md Remove section on thread identity: this is not part of open-source Luau and as such is now confusing. --- docs/_pages/sandbox.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/_pages/sandbox.md b/docs/_pages/sandbox.md index 8457cd11..409a0929 100644 --- a/docs/_pages/sandbox.md +++ b/docs/_pages/sandbox.md @@ -46,16 +46,6 @@ This is using the VM feature that is not accessible from scripts, that prevents By itself this would mean that code that runs in Luau can't use globals at all, since assigning globals would fail. While this is feasible, in Roblox we solve this by creating a new global table for each script, that uses `__index` to point to the builtin global table. This safely sandboxes the builtin globals while still allowing writing globals from each script. This also means that short of exposing special shared globals from the host, all scripts are isolated from each other. -## Thread identity - -Environment-level sandboxing is sufficient to implement separation between trusted code and untrusted code, assuming that `getfenv`/`setfenv` are either unavailable (removed from the globals), or that trusted code never interfaces with untrusted code (which prevents untrusted code from ever getting access to trusted functions). When running trusted code, it's possible to inject extra globals from the host into that global table, providing access to special APIs. - -However, in some cases it's desirable to restrict access to functions that are exposed both to trusted and untrusted code. For example, both may have access to `game` global, but `game` may expose methods that should only work from trusted code. - -To achieve this, each thread in Luau has a security identity, which can only be set by the host. Newly created threads inherit identities from the parent thread, and functions exposed from the host can validate the identity of the calling thread. This makes it possible to provide APIs to trusted code while limiting the access from untrusted code. - -> Note: to achieve an even stronger guarantee of isolation between trusted and untrusted code, it's possible to run it in different Luau VMs, which is what Roblox does for extra safety. - ## `__gc` Lua 5.1 exposes a `__gc` metamethod for userdata, which can be used on proxies (`newproxy`) to hook into garbage collector. Later versions of Lua extend this mechanism to work on tables.