2013-02-17 2 views
5

배경 나는 게임 Bitfighter에 Watusimoto 작업루아, C++ 및 사라지고 메타 테이블

. 우리는 LuaWrapper 변형을 사용하여 우리의 C++ 객체를 게임의 루아 객체와 연결합니다. 우리는 또한 벡터 작업을 가속화하기 위해 lua-vec이라는 Lua 변형을 사용합니다.

우리는 우리를 벗어난 버그를 해결하기 위해 노력해 왔습니다. 손상된 메타 테이블을 제안하는 임의의 충돌이 발생합니다. 문제에 대한 Watusimoto의 게시물은 here을 참조하십시오. 나는 부패한 메타 테이블 때문에 이것이 맞는지 확신 할 수 없으며, 내가 여기서 물어보고 싶은 아주 이상한 행동을 보았다.

예를 들어 문제점 현시

, 우리는 객체를 생성하고이 같은 수준에 추가 :

t = TextItem.new() 
t:setText("hello") 
levelgen:addItem(t) 

그러나, 게임 것이다 때때로 (항상) 충돌. 오류로 : 위에서 언급 한 Watusimoto의 게시물에 대한 응답으로 주어진 제안을 사용

attempt to call missing or unknown method 'addItem' (a nil value) 

, 나는에 마지막 줄을 변경 한 다음

local ok, res = pcall(function() levelgen:addItem(t) end) 

if not ok then 
    local s = "Invalid levelgen value: "..tostring(levelgen).." "..type(levelgen).."\n" 

    for k, v in pairs(getmetatable(levelgen)) do 
     s = s.."meta "..tostring(k).." "..tostring(v).."\n" 
    end 

    error(res..s) 
end 

때 어떤 경우는 levelgen의 메타 테이블을 출력 그것으로부터 메소드를 호출하는 것은 잘못되었습니다.

그러나

, 그것이 실패하고 메타 테이블을 출력 할 때이, 미친, 메타 테이블은 (정확한 addItem 통화와 모든 것을) 어떻게해야 정확히입니다. 스크립트가로드 될 때 levelgen에 대한 메타 테이블을 인쇄하고 위의 pcall을 사용하여 실패하면 모두 동일하며 모든 호출과 userdata에 대한 포인터가 같아야합니다.

마치 levelgen에 대한 메타 테이블이 무작위로 자발적으로 사라지는 것처럼 보입니다.

아무도 어떤 일이 벌어지고 있는지 알 수 있습니까?

당신에게

참고 감사합니다이 만 levelgen 개체 발생하지 않습니다. 예를 들어, 위에서 언급 한 TestItem 개체에서도 발생했습니다. 사실, 같은 코드 같은 오류 메시지가 missing or unknown method 'setText' (a nil value)

+0

Valgrind에서 코드를 실행 해 보셨습니까? C++에서 메모리 손상 문제가있을 수 있습니다. – nneonneo

+0

안녕하세요, 예, 우리는 valgrind를 통해 여러 번 실행했습니다. 거기에 있던 메모리 버그를 수정 한 후에도 문제는 여전히 지속됩니다. – raptor

+0

매우 궁금합니다. 문제를 간단한 테스트 케이스로 줄일 수 있습니까? – nneonneo

답변

1

업스트림 (커밋 3c54015) LuaWrapper와 병합 한 후이 문제는 사라졌습니다. LuaWrapper에 버그가있는 것 같습니다.

감사합니다. Alex!

2

어떤 신비와 마찬가지로,이 층으로 층을 벗겨 할 필요가있는 라인 t:setText("hello")와 다른 개발자의 컴퓨터에 선 levelgen:addItem(t)하지만 충돌에서 내 컴퓨터에 충돌합니다. 루아가 진행하는 것과 동일한 단계를 거치며 취해진 경로가 예상과 다른 곳을 찾아내는 것이 좋습니다.

getmetatable(levelgen).__index은 무엇을 반환합니까? 그것이 표라면 addItem의 내용을 확인하십시오. 그것이 함수라면, (table, "addItem")으로 호출하고 리턴하는 것을보십시오.

getmetatable이 호출 전후에 동일한 객체에 대한 참조를 반환하는지 확인하십시오 (실패한 경우).

호출이 진행되는 여러 단계의 메타 테이블 간접 지정이 있습니까? 그렇다면 명시 적 호출과 동일한 경로를 따라 차이점을 확인하십시오.

다른 참조가 없으면 값이 사라질 수있는 weak 키를 사용하고 있습니까?

실패했을 때 "기본"값을 제공하고 나중에이 방법을 다시 "찾았"는지 계속 볼 수 있습니까? 아니면 고장 났을 때마다 그때마다 전화가 끊어 졌습니까?

addItem에 적절한 값을 저장하고 손상된 것을 감지하면 "수정"하면 어떻게됩니까?

단순히 오류를 처리하고 10 번만 호출하면 어떻게됩니까? 적어도 한 번 이상 유효한 결과를 보여 주겠습니까 (실패한 후)? 100 번? 똑같은 방법으로 전화를 걸면 실패할까요? 이렇게하면 재현성있는 오류가 발생하는 데 도움이 될 수 있습니다.

더 구체적인 질문을 제공하기 위해 LuaWrapper에 익숙하지 않지만, 내가 당신이라면 이러한 조치를 취해야합니다.

struct Foo 
{ 
    Bar bar; 
    // Other fields follow 
} 

그리고 당신은 LuaWrapper를 통해 루아에 푸과 바 모두를 노출했다고 : 난 강력하게 문제를 의심

2

는이 유사한 클래스 또는 구조체를 가지고있다. 여기서 중요한 점은 barFoo 구조체의 첫 번째 필드라는 것입니다. 또는 다른 기본 클래스에서 상속 한 클래스가있을 수 있으며 파생 클래스와 기본 클래스가 모두 LuaWrapper에 노출되어 있습니다.

LuaWrapper는 Identifier라는 함수를 사용하여 각 객체를 고유하게 추적합니다 (지정된 객체가 이미 Lua 상태에 추가되었는지 여부와 같음). 기본적으로 오브젝트 주소를 키로 사용합니다. 위와 같은 경우 Foo와 Bar 모두 메모리에서 같은 주소를 가질 수 있으므로 LuaWrapper가 혼동을 일으킬 수 있습니다.

이렇게하면 메서드를 조회 할 때 잘못된 개체의 메타 테이블을 가져올 수 있습니다. 분명히 잘못된 메타 테이블을보고 있기 때문에 원하는 메서드를 찾지 못하기 때문에 메타 테이블이 신비하게 항목을 잃어 버린 것처럼 나타납니다.

하나의 거대한 더미가 아닌 각 객체의 데이터를 추적하는 변경 사항을 확인했습니다. LuaWrapper를 저장소에서 최신 버전으로 업데이트하면 문제가 해결 될 것이라고 확신합니다.

+1

당신의 진단이 맞을 수도 있지만 잘못된 이유가 있다고 생각합니다. 클래스가 혼란 스러울 수는 있지만 상속 때문에가 아니라, 우리가 신속하게 객체를 순환시키고 있기 때문에 루아의 가비지 컬렉션이 일을 정리할 기회를 갖기 전에 C++에서 다른 객체 유형에 대한 주소를 재 할당 할 수 있습니다. 서브 클래 싱은 여기서 문제가되지 않습니다. 즉, 최근 LuaWrapper를 변경하면 문제가 해결 될 수도 있습니다. – Watusimoto

+0

와우, 이것을 찾아 주셔서 감사합니다! 우리는 변경 사항을 포팅하여 알려드립니다. – raptor

+0

흠, Lua GC가 gc-ing보다 빨리 주소를 재사용하는 경우는 고려하지 않았습니다. 아마도 LuaWrapper가 주어진 객체를 추적하고 있음을 완전히 잊도록 지시하는 일종의 luaW_forget이 필요할 수도 있습니다. 다른 해결책은 각 객체에 대해 고유 한 값을 보장하는 고유 한 식별자 함수를 작성하는 것입니다 (객체를 고유하게 식별 할 수있는 방법이있는 경우). – Alex