ThePhD / sol2

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
http://sol2.rtfd.io/
MIT License
4.06k stars 492 forks source link

A const C++ container can be modified in Lua (want it to be truly const) #1587

Open totalgee opened 3 months ago

totalgee commented 3 months ago

I'd like to expose a const container (here it happens to be a std::vector) to Lua via Sol, so it can be iterated/accessed there but not modified. I thought that exposing a const ref to the thing (rather than a ref) would prevent modifications to it via Lua, but there is no error when I try to add elements in various ways; I actually manage to modify the "const" declared C++ vector!

Compiler: Visual Studio 2022, C++17 or C++20 OS: Windows 11 Pro

Here is an example that shows the problem, and what I'm trying to do. It's basically a slightly modified version of your example from the documentation, but where I tried to make the vector constant:

#include "sol/sol.hpp"

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::os, sol::lib::string);

    lua.script(R"lua(
function printContainer(x)
    print("\ncontainer has:")
    for k = 1, #x do
        v = tostring(x[k])
        print("\t", k, v)
    end
end
    )lua");

    sol::function printContainer = lua["printContainer"];

    // Expose a constant vector to Lua
    // (first tried exposing as a cref, and then I even tried setting the underlying variable as const!)
    auto const arr = std::vector<int>{ 2, 4, 6, 8, 10 };
    lua["arr"] = std::cref(arr);
    printContainer(lua["arr"]);
    std::cout << "Size of C++ arr: " << arr.size() << '\n';

    // Presumably we shouldn't be able to get a non-const reference to it...?
    std::vector<int>& reference_to_arr = lua["arr"];
    reference_to_arr.push_back(12);

    // See *6* elements printed out (but it's supposed to be const)
    printContainer(lua["arr"]);
    std::cout << "Size of C++ arr: " << arr.size() << '\n';

    // Modify it from Lua
    lua.script(R"(
arr:add(28)
    )");

    // See *7* elements printed out (again, it's intended to be const)
    printContainer(lua["arr"]);
    std::cout << "Size of C++ arr: " << arr.size() << '\n';

    return 0;
}

The program outputs:

container has:
                1       2
                2       4
                3       6
                4       8
                5       10
Size of C++ arr: 5

container has:
                1       2
                2       4
                3       6
                4       8
                5       10
                6       12
Size of C++ arr: 6

container has:
                1       2
                2       4
                3       6
                4       8
                5       10
                6       12
                7       28
Size of C++ arr: 7

Ideally, I'd like to have the exposing as const "just work", but I guess it may be necessary to create my own container type...? I would expect it to give an error if I try to modify it. Maybe something like what happens if I use a const variable in Lua and then try to change it:

local x <const> = 3
x = 7

Which produces:

[sol2] An error occurred and has been passed to an error handler: sol: syntax error: [string "..."]:3: attempt to assign to const variable 'x'