僕と少女の思考録

低浮上でメモするブログです。

自己流Luaのクラス定義

自分の使っているLuaのクラス実装は以下の機能を持つすごいやつ

  • インスタンスメンバーとクラスメンバーの分離
  • クラスの継承
  • メソッドのオーバーライド
  • スーパークラスのメソッドの呼び出し
  • メタテーブルを利用した省メモリな実装
  • あまりごちゃごちゃしない

投げやりの文章だが睡魔が襲ってきたのでやむなし。実装例は上げておくので詳しい解説は明日以降にする。

Class definition in Lua

LuaJIT(2.0.5)のlua_pcall()でアクセス違反がでる問題について

おそらく他にも引っ掛かった人が居そうなので投稿。


以下のコードを見ていただきたい。

C言語
#include <stdio.h>
#include <lua.hpp>

/* Lua専用関数.
 */
int luaF_CFunction(lua_State* L)
{
    const char* str = luaL_checkstring(L,1);

    printf("%s\(・ ・ ))゜ しまりん", str);
    return 1;
}

int main()
{
    // Luaステートの作成
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);
    
    // スクリプトファイルの読み込み
    if( luaL_loadfile(L, "script.lua") || lua_pcall(L, 0, 0, 0) )
    {
        printf("%s\n", lua_tostring(L,lua_gettop(L)));
    }

    // Cの関数の登録
    static const struct luaL_Reg fs[]
    {
        {"CFunction", &luaF_CFunction},
        {nullptr,nullptr}
    };
    luaL_register(L, "MyLib", fs);


    /* -- Luaの関数呼び出し(今日の主役) --
    */
    lua_getglobal(L,"main");
    if( lua_pcall(L, 0, 0, 0)!=0 )
    {
        printf("%s\n", lua_tostring(L, lua_gettop(L)));
    }
    getchar();


    // 後始末
    lua_close(L);
    return 0;
}
Lua
function main()
    -- C言語の関数呼び出し
    MyLib.CFunction("なでしこ ( >ワ<)ノ")
end

一見すると何の変哲もないソースコード。ただLua側からC言語の関数を呼び出して終わるだけのもの。



こいつがでるまでは...

f:id:masterexaam:20181203101522p:plain

その名も「アクセス違反」。自分の場合はゲームエンジンへの組み込みテスト中にこれが起こった。デバックしてみると関数の呼び出し自体は成功している模様。

急遽別途のプロジェクトを作成して同じものを動かしてみると、なぜかこっちは通常どおり動作する。

ネットを開きあれやこれや.....

原因

結論からいうとLuaJITでかつx64で動作させた場合のみこれが起こる。根本的な原因は不明だが、どうやらLuaJITはもともとx64上で問題を抱えていることと、ガーベッジコレクションが関係しているらしい。*1*2

対処法

x64を使わない

比較的簡単にできてリスクも少なくて済む。しかし、x64上での動作を余儀なくされる場合にはあまり意味をなさない。

コンパイラオプションの変更

以下のオプションでライブラリをビルドする。

msvcbuild gc64

これでひとまずは、アクセス違反が発生しなくなった。ただ、詳細な検証を行っていないため今後別の問題が発生するかどうかはわからない。