diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 572e037..deb8be8 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -13,9 +13,7 @@ on: jobs: callgrind: - name: callgrind strategy: - fail-fast: false matrix: os: [ubuntu-22.04] benchResultsRepo: @@ -44,9 +42,9 @@ jobs: run: | python bench/bench.py --callgrind --vm "./luau-gcc -O2" | tee -a bench-gcc-output.txt - - name: Run benchmark (bench-clang) + - name: Run benchmark (bench) run: | - python bench/bench.py --callgrind --vm "./luau -O2" | tee -a bench-clang-output.txt + python bench/bench.py --callgrind --vm "./luau -O2" | tee -a bench-output.txt - name: Run benchmark (analyze) run: | @@ -78,13 +76,13 @@ jobs: token: ${{ secrets.BENCH_GITHUB_TOKEN }} path: "./gh-pages" - - name: Store results (bench-clang) + - name: Store results (bench) uses: Roblox/rhysd-github-action-benchmark@v-luau with: name: callgrind clang tool: "benchmarkluau" - output-file-path: ./bench-clang-output.txt - external-data-json-path: ./gh-pages/bench-clang.json + output-file-path: ./bench-output.txt + external-data-json-path: ./gh-pages/bench.json - name: Store results (bench-gcc) uses: Roblox/rhysd-github-action-benchmark@v-luau diff --git a/VM/src/lapi.cpp b/VM/src/lapi.cpp index bb994fb..77788e4 100644 --- a/VM/src/lapi.cpp +++ b/VM/src/lapi.cpp @@ -1209,7 +1209,10 @@ void* lua_newuserdatadtor(lua_State* L, size_t sz, void (*dtor)(void*)) { luaC_checkGC(L); luaC_checkthreadsleep(L); - Udata* u = luaU_newudata(L, sz + sizeof(dtor), UTAG_IDTOR); + size_t as = sz + sizeof(dtor); + if (as < sizeof(dtor)) + as = SIZE_MAX; // Will cause a memory error in luaU_newudata. + Udata* u = luaU_newudata(L, as, UTAG_IDTOR); memcpy(&u->data + sz, &dtor, sizeof(dtor)); setuvalue(L, L->top, u); api_incr_top(L); diff --git a/docs/_pages/compatibility.md b/docs/_pages/compatibility.md index bdb3d81..1c15e9b 100644 --- a/docs/_pages/compatibility.md +++ b/docs/_pages/compatibility.md @@ -70,6 +70,7 @@ Sandboxing challenges are [covered in the dedicated section](sandbox). | `bit32` library | ✔️ | | | `string.gsub` is stricter about using `%` on special characters only | ✔️ | | | light C functions | 😞 | this changes semantics of fenv on C functions and has complex implications wrt runtime performance | +| NaN keys are supported for tables with `__newindex` | ✔️ | | Two things that are important to call out here are various new metamethods for tables and yielding in metamethods. In both cases, there are performance implications to supporting this - our implementation is *very* highly tuned for performance, so any changes that affect the core fundamentals of how Lua works have a price. To support yielding in metamethods we'd need to make the core of the VM more involved, since almost every single "interesting" opcode would need to learn how to be resumable - which also complicates future JIT/AOT story. Metamethods in general are important for extensibility, but very challenging to deal with in implementation, so we err on the side of not supporting any new metamethods unless a strong need arises. diff --git a/docs/_pages/lint.md b/docs/_pages/lint.md index fd3c595..681a275 100644 --- a/docs/_pages/lint.md +++ b/docs/_pages/lint.md @@ -326,7 +326,6 @@ Luau uses comments that start from `!` to control certain aspects of analysis, f --!nostrict -- Unknown comment directive 'nostrict'; did you mean 'nonstrict'?" ``` -``` ## IntegerParsing (27) diff --git a/rfcs/generalized-iteration.md b/rfcs/generalized-iteration.md index 9967109..c28156f 100644 --- a/rfcs/generalized-iteration.md +++ b/rfcs/generalized-iteration.md @@ -51,8 +51,10 @@ end To support self-iterating objects, we modify the iteration protocol as follows: instead of simply expanding the result of expression `iter` into three variables (`gen`, `state` and `index`), we check if the first result has an `__iter` metamethod (which can be the case if it's a table, userdata or another composite object (e.g. a record in the future). If it does, the metamethod is called with `gen` as the first argument, and the returned three values replace `gen`/`state`/`index`. This happens *before* the loop: ```lua -if getmetatable(gen) and getmetatable(gen).__iter then - gen, state, index = getmetatable(gen).__iter(gen) +local genmt = rawgetmetatable(gen) -- pseudo code for getmetatable that bypasses __metatable +local iterf = genmt and rawget(genmt, "__iter") +if iterf then + gen, state, index = iterf(gen) end ``` diff --git a/tests/Conformance.test.cpp b/tests/Conformance.test.cpp index e07ba12..17c7ac5 100644 --- a/tests/Conformance.test.cpp +++ b/tests/Conformance.test.cpp @@ -716,6 +716,23 @@ TEST_CASE("Reference") CHECK(dtorhits == 2); } +TEST_CASE("NewUserdataOverflow") +{ + StateRef globalState(luaL_newstate(), lua_close); + lua_State* L = globalState.get(); + + lua_pushcfunction(L, [](lua_State* L1) { + // The following userdata request might cause an overflow. + lua_newuserdatadtor(L1, SIZE_MAX, [](void* d){}); + // The overflow might segfault in the following call. + lua_getmetatable(L1, -1); + return 0; + }, "PCall"); + + CHECK(lua_pcall(L, 0, 0, 0) == LUA_ERRRUN); + CHECK(strcmp(lua_tostring(L, -1), "memory allocation error: block too big") == 0); +} + TEST_CASE("ApiTables") { StateRef globalState(luaL_newstate(), lua_close);