diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index 3f084373..5f47cf0a 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -51,7 +51,7 @@ jobs: - name: Build Lua ${{ matrix.lua.version }} (C++17) working-directory: ${{runner.workspace}}/build17 run: | - cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target \ LuaBridgeTests${{ matrix.lua.suffix }} \ LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ @@ -59,7 +59,7 @@ jobs: - name: Test Lua ${{ matrix.lua.version }} (C++17) working-directory: ${{runner.workspace}}/build17 - run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure - name: Configure C++20 working-directory: ${{runner.workspace}}/build20 @@ -68,7 +68,7 @@ jobs: - name: Build Lua ${{ matrix.lua.version }} (C++20) working-directory: ${{runner.workspace}}/build20 run: | - cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target \ LuaBridgeTests${{ matrix.lua.suffix }} \ LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ @@ -76,7 +76,7 @@ jobs: - name: Test Lua ${{ matrix.lua.version }} (C++20) working-directory: ${{runner.workspace}}/build20 - run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure - name: Configure C++23 working-directory: ${{runner.workspace}}/build23 @@ -85,7 +85,7 @@ jobs: - name: Build Lua ${{ matrix.lua.version }} (C++23) working-directory: ${{runner.workspace}}/build23 run: | - cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target \ LuaBridgeTests${{ matrix.lua.suffix }} \ LuaBridgeTests${{ matrix.lua.suffix }}LuaC \ LuaBridgeTests${{ matrix.lua.suffix }}Noexcept \ @@ -93,7 +93,7 @@ jobs: - name: Test Lua ${{ matrix.lua.version }} (C++23) working-directory: ${{runner.workspace}}/build23 - run: ctest --parallel $(nproc) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTests${{ matrix.lua.suffix }}" --output-on-failure luajit: runs-on: macos-latest @@ -116,13 +116,13 @@ jobs: - name: Build LuaJIT (C++17) working-directory: ${{runner.workspace}}/build17 run: | - cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target \ LuaBridgeTestsLuaJIT \ LuaBridgeTestsLuaJITNoexcept - name: Test LuaJIT (C++17) working-directory: ${{runner.workspace}}/build17 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsLuaJIT" --output-on-failure - name: Configure C++20 working-directory: ${{runner.workspace}}/build20 @@ -131,13 +131,13 @@ jobs: - name: Build LuaJIT (C++20) working-directory: ${{runner.workspace}}/build20 run: | - cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target \ LuaBridgeTestsLuaJIT \ LuaBridgeTestsLuaJITNoexcept - name: Test LuaJIT (C++20) working-directory: ${{runner.workspace}}/build20 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsLuaJIT" --output-on-failure - name: Configure C++23 working-directory: ${{runner.workspace}}/build23 @@ -146,13 +146,13 @@ jobs: - name: Build LuaJIT (C++23) working-directory: ${{runner.workspace}}/build23 run: | - cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target \ + cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target \ LuaBridgeTestsLuaJIT \ LuaBridgeTestsLuaJITNoexcept - name: Test LuaJIT (C++23) working-directory: ${{runner.workspace}}/build23 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuaJIT" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsLuaJIT" --output-on-failure luau: runs-on: macos-latest @@ -174,11 +174,11 @@ jobs: - name: Build Luau (C++17) working-directory: ${{runner.workspace}}/build17 - run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau + run: cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target LuaBridgeTestsLuau - name: Test Luau (C++17) working-directory: ${{runner.workspace}}/build17 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsLuau" --output-on-failure - name: Configure C++20 working-directory: ${{runner.workspace}}/build20 @@ -186,11 +186,11 @@ jobs: - name: Build Luau (C++20) working-directory: ${{runner.workspace}}/build20 - run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau + run: cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target LuaBridgeTestsLuau - name: Test Luau (C++20) working-directory: ${{runner.workspace}}/build20 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsLuau" --output-on-failure - name: Configure C++23 working-directory: ${{runner.workspace}}/build23 @@ -198,11 +198,11 @@ jobs: - name: Build Luau (C++23) working-directory: ${{runner.workspace}}/build23 - run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsLuau + run: cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target LuaBridgeTestsLuau - name: Test Luau (C++23) working-directory: ${{runner.workspace}}/build23 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsLuau" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsLuau" --output-on-failure ravi: runs-on: macos-latest @@ -224,11 +224,11 @@ jobs: - name: Build Ravi (C++17) working-directory: ${{runner.workspace}}/build17 - run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi + run: cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target LuaBridgeTestsRavi - name: Test Ravi (C++17) working-directory: ${{runner.workspace}}/build17 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsRavi" --output-on-failure - name: Configure C++20 working-directory: ${{runner.workspace}}/build20 @@ -236,11 +236,11 @@ jobs: - name: Build Ravi (C++20) working-directory: ${{runner.workspace}}/build20 - run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi + run: cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target LuaBridgeTestsRavi - name: Test Ravi (C++20) working-directory: ${{runner.workspace}}/build20 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsRavi" --output-on-failure - name: Configure C++23 working-directory: ${{runner.workspace}}/build23 @@ -248,8 +248,8 @@ jobs: - name: Build Ravi (C++23) working-directory: ${{runner.workspace}}/build23 - run: cmake --build . --config $BUILD_TYPE --parallel $(nproc) --target LuaBridgeTestsRavi + run: cmake --build . --config $BUILD_TYPE --parallel $(sysctl -n hw.ncpu) --target LuaBridgeTestsRavi - name: Test Ravi (C++23) working-directory: ${{runner.workspace}}/build23 - run: ctest --parallel $(nproc) -R "LuaBridgeTestsRavi" --output-on-failure + run: ctest --parallel $(sysctl -n hw.ncpu) -R "LuaBridgeTestsRavi" --output-on-failure diff --git a/Source/LuaBridge/detail/LuaHelpers.h b/Source/LuaBridge/detail/LuaHelpers.h index 86d6d552..703942db 100644 --- a/Source/LuaBridge/detail/LuaHelpers.h +++ b/Source/LuaBridge/detail/LuaHelpers.h @@ -135,6 +135,8 @@ inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debug [[noreturn]] inline void lua_error_x(lua_State* L) { lua_error(L); + + detail::unreachable(); } inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) @@ -184,6 +186,8 @@ inline void lua_pushcclosure_x(lua_State* L, lua_CFunction fn, const char* debug [[noreturn]] inline void lua_error_x(lua_State* L) { lua_error(L); + + detail::unreachable(); } inline int lua_getstack_x(lua_State* L, int level, lua_Debug* ar) diff --git a/Source/LuaBridge/detail/LuaRef.h b/Source/LuaBridge/detail/LuaRef.h index 4fb4e00c..f3658b2f 100644 --- a/Source/LuaBridge/detail/LuaRef.h +++ b/Source/LuaBridge/detail/LuaRef.h @@ -1836,11 +1836,29 @@ class LuaRef : public LuaRefBase const void* getPointer() const { #if LUABRIDGE_SAFE_STACK_CHECKS - if (! lua_checkstack(m_L, 1)) + if (! lua_checkstack(m_L, 3)) return nullptr; #endif lua_rawgeti(m_L, LUA_REGISTRYINDEX, m_ref); + + if (lua_isuserdata(m_L, -1) && lua_getmetatable(m_L, -1)) + { + const void* key = static_cast(detail::getTypeKey()); + lua_pushlightuserdata(m_L, const_cast(key)); + lua_rawget(m_L, -2); + const bool isLuaBridgeType = lua_isstring(m_L, -1); + lua_pop(m_L, 2); + + if (isLuaBridgeType) + { + const auto* ud = static_cast(lua_touserdata(m_L, -1)); + const void* ptr = ud->getPointer(); + lua_pop(m_L, 1); + return ptr; + } + } + const void* ptr = lua_topointer(m_L, -1); lua_pop(m_L, 1); diff --git a/Source/LuaBridge/detail/Userdata.h b/Source/LuaBridge/detail/Userdata.h index 21210c52..431f3823 100644 --- a/Source/LuaBridge/detail/Userdata.h +++ b/Source/LuaBridge/detail/Userdata.h @@ -363,17 +363,18 @@ class Userdata || isInstance(L, index, detail::getConstRegistryKey()); } -protected: - Userdata() = default; - /** * @brief Get an untyped pointer to the contained class. */ +public: void* getPointer() const noexcept { return m_p; } +protected: + Userdata() = default; + void* m_p = nullptr; // subclasses must set this }; diff --git a/Tests/Source/LuaRefTests.cpp b/Tests/Source/LuaRefTests.cpp index 91b125a3..b1fc0583 100644 --- a/Tests/Source/LuaRefTests.cpp +++ b/Tests/Source/LuaRefTests.cpp @@ -2184,3 +2184,135 @@ TEST_F(LuaRefTests, PreservesLuaTableMutations) ASSERT_TRUE(secondResult); EXPECT_EQ(200, *secondResult); } + +TEST_F(LuaRefTests, GetPointerDefaultConstructed) +{ + luabridge::LuaRef ref(L); + EXPECT_EQ(nullptr, ref.getPointer()); +} + +TEST_F(LuaRefTests, GetPointerNil) +{ + runLua("result = nil"); + EXPECT_EQ(nullptr, result().getPointer()); + + luabridge::LuaRef nilRef(L, luabridge::LuaNil()); + EXPECT_EQ(nullptr, nilRef.getPointer()); +} + +TEST_F(LuaRefTests, GetPointerBoolean) +{ + runLua("result = true"); + EXPECT_EQ(nullptr, result().getPointer()); + + runLua("result = false"); + EXPECT_EQ(nullptr, result().getPointer()); +} + +TEST_F(LuaRefTests, GetPointerNumber) +{ + runLua("result = 42"); + EXPECT_EQ(nullptr, result().getPointer()); + + runLua("result = 3.14"); + EXPECT_EQ(nullptr, result().getPointer()); +} + +TEST_F(LuaRefTests, GetPointerString) +{ + runLua("result = 'hello'"); + +#if LUA_VERSION_NUM >= 504 || LUABRIDGE_ON_LUAU || LUABRIDGE_ON_LUAJIT + // Lua 5.4+, Luau, and LuaJIT return a pointer for strings via lua_topointer + EXPECT_NE(nullptr, result().getPointer()); +#else + EXPECT_EQ(nullptr, result().getPointer()); +#endif +} + +TEST_F(LuaRefTests, GetPointerTable) +{ + runLua("result = {}"); + EXPECT_NE(nullptr, result().getPointer()); +} + +TEST_F(LuaRefTests, GetPointerTableIdentity) +{ + runLua("result = {}"); + const void* p1 = result().getPointer(); + const void* p2 = result().getPointer(); + EXPECT_NE(nullptr, p1); + EXPECT_EQ(p1, p2); +} + +TEST_F(LuaRefTests, GetPointerDistinctTables) +{ + runLua("t1 = {}; t2 = {}"); + auto t1 = luabridge::getGlobal(L, "t1"); + auto t2 = luabridge::getGlobal(L, "t2"); + + const void* p1 = t1.getPointer(); + const void* p2 = t2.getPointer(); + EXPECT_NE(nullptr, p1); + EXPECT_NE(nullptr, p2); + EXPECT_NE(p1, p2); +} + +TEST_F(LuaRefTests, GetPointerFunction) +{ + runLua("result = function() end"); + EXPECT_NE(nullptr, result().getPointer()); +} + +TEST_F(LuaRefTests, GetPointerLightUserdata) +{ + int dummy = 0; + lua_pushlightuserdata(L, &dummy); + auto ref = luabridge::LuaRef::fromStack(L); + EXPECT_EQ(&dummy, ref.getPointer()); +} + +TEST_F(LuaRefTests, GetPointerLightUserdataNull) +{ + lua_pushlightuserdata(L, nullptr); + auto ref = luabridge::LuaRef::fromStack(L); + EXPECT_EQ(nullptr, ref.getPointer()); +} + +TEST_F(LuaRefTests, GetPointerUserdata) +{ + void* p = lua_newuserdata(L, 100); + auto ref = luabridge::LuaRef::fromStack(L); + EXPECT_NE(nullptr, ref.getPointer()); + EXPECT_EQ(p, ref.getPointer()); +} + +TEST_F(LuaRefTests, GetPointerRegisteredClass) +{ + luabridge::getGlobalNamespace(L).beginClass("Class").endClass(); + + Class obj; + auto ref = luabridge::LuaRef(L, &obj); + EXPECT_EQ(&obj, ref.getPointer()); +} + +TEST_F(LuaRefTests, GetPointerThread) +{ + lua_State* threadL = lua_newthread(L); + lua_pushthread(threadL); + auto ref = luabridge::LuaRef::fromStack(L); + EXPECT_NE(nullptr, ref.getPointer()); + EXPECT_EQ(threadL, ref.getPointer()); +} + +#if LUABRIDGE_SAFE_STACK_CHECKS +TEST_F(LuaRefTests, GetPointerStackOverflow) +{ + runLua("result = {}"); + auto ref = result(); + exhaustStackSpace(); + const void* p = ref.getPointer(); + lua_settop(L, 0); + EXPECT_EQ(nullptr, p); +} +#endif