Skip to content

Commit

Permalink
Merge branch 'Roblox:master' into webrepl
Browse files Browse the repository at this point in the history
  • Loading branch information
MathematicalDessert committed Nov 6, 2021
2 parents 04feb12 + c6de3bd commit bb987da
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 28 deletions.
5 changes: 0 additions & 5 deletions Ast/src/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2379,15 +2379,12 @@ AstArray<AstTypeOrPack> 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
Expand All @@ -2399,8 +2396,6 @@ AstArray<AstTypeOrPack> Parser::parseTypeParams()

if (typePack)
{
seenPack = true;

if (FFlag::LuauTypeAliasPacks) // Type packs are recorded only is we can handle them
parameters.push_back({{}, typePack});
}
Expand Down
29 changes: 22 additions & 7 deletions CLI/Analyze.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Luau::SyntaxError>(&error.data))
report(format, name, error.location, "SyntaxError", syntaxError->message.c_str());
else
Expand All @@ -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))
{
Expand All @@ -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);

Expand Down Expand Up @@ -115,7 +120,12 @@ struct CliFileResolver : Luau::FileResolver
{
if (Luau::AstExprConstantString* expr = node->as<Luau::AstExprConstantString>())
{
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}};
}
Expand Down Expand Up @@ -236,8 +246,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
Expand All @@ -256,5 +273,3 @@ int main(int argc, char** argv)

return (format == ReportFormat::Luacheck) ? 0 : failed;
}


10 changes: 7 additions & 3 deletions CLI/Repl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,13 @@ static int lua_require(lua_State* L)
return finishrequire(L);
lua_pop(L, 1);

std::optional<std::string> source = readFile(name + ".lua");
std::optional<std::string> 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);
Expand Down Expand Up @@ -547,4 +551,4 @@ int main(int argc, char** argv)
return failed;
}
}
#endif
#endif
11 changes: 9 additions & 2 deletions Compiler/src/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2465,9 +2465,10 @@ struct Compiler
}
else if (node->is<AstStatBreak>())
{
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();
Expand All @@ -2478,12 +2479,13 @@ struct Compiler
}
else if (AstStatContinue* stat = node->as<AstStatContinue>())
{
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();
Expand Down Expand Up @@ -2900,6 +2902,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:
Expand Down
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 0 additions & 10 deletions docs/_pages/sandbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions tests/Compiler.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit bb987da

Please sign in to comment.