UE 5.6.1에서 google protobuf 사용 시 Free checkf 실패

질문에 참조된 게시물: [UE 5.6.1 std::streamstring의 Free 시 GetAllocationSizeExternal 크래시 [Content removed]

관련하여 AGDE를 사용하여 크래시 발생 시의 콜스택을 확인하여 전달드립니다.

다시 확인드리면 문제는 TMallocBinnedCommon<FMallocBinned3>::GetAllocationSizeExternal() 안의 checkf가 실패했기 때문입니다.

즉, FMemory::Free로 넘어온 포인터 0x6f39501d60이 UE 메모리 할당자가 관리하던 블록이 아니라고 판단되어 치명적 로그 를 올리며 크래시가 난 것입니다.

google protobuf는 많은 곳에서 일반적으로 사용되는 것인데, 여기에서 문제가 발생하였기 때문에 언리얼에서 이를 인지하고 해결할 예정이 있는지를 질문하고자 합니다.

혹은 이미 해결한 커밋이 있는지도 궁금합니다.

추가로, MallocAnsi 사용 제안을 해주셨는데요. 문제가 해결된다고 하더라도 성능이 저하될 것이 염려됩니다.

MallcBinned3과 비교했을 때 MallocAnsi를 사용해도 크게 문제가 없을지, 내부적으로 확인된 자료나 내용이 있다면 공유 부탁 드리겠습니다.

안녕하세요.

Google ProtoBuf는 서드 파티 플러그인으로, 해당 사항 관련하여 아직까지 공식적으로 수정 계획이 있거나

관련 티켓은 생성되지 않은 것으로 보입니다.

언리얼 엔진은 자체 할당자를 사용하고 있으며

언리얼 외부에서 할당된 메모리를 언리얼 할당자를 통해 삭제하면 보내주신 콜스택과 같이 일반적으로 충돌이 발생합니다.

(반대의 경우에도 마찬가지 입니다)

이를 해결하기 위해 아래와 같은 방법들을 시도할 수 있습니다.

  • Static Linking 사용

언리얼 엔진은 C++ new(), delete() 연산자를 오버로딩하며, 이는 언리얼 빌드 환경에서만 작동합니다.

따라서 외부 소스 코드를 프로젝트에 포함하고 UBT로 컴파일하면, 라이브러리 내부의 모든

new(), delete() 호출이 링크 단계에서 언리얼 엔진의 전역 operator로 해석될 수 있어 보입니다.

다만, 라이브러리의 구현 방식에 따라 연결이 보장되지 않을 수 있으므로

관련 객체가 생성되고 소멸되는 위치를 디버깅하여 호출이 올바르게 이루어지고 있는지 검증해야 합니다.

  • Custom Allocator 사용

ModuleBoilerplate.h와 CL 31807641에서 서드파티 메모리 처리를 언리얼 엔진 방식으로 래핑하는 매크로를 확인할 수 있습니다.

#define UE_DEFINE_FMEMORY_WRAPPERS \
void* FMemory_Malloc ( size_t Size, size_t Alignment) { return FMemory::Malloc( Size ? Size : 1, Alignment ); } \
void* FMemory_Realloc( void* Original, size_t Size, size_t Alignment ) { return FMemory::Realloc(Original, Size ? Size : 1, Alignment ); } \
void  FMemory_Free   ( void *Ptr) { FMemory::Free( Ptr ); }

일부 서드파티 라이브러리는 Custom Allocator 함수를 제공하며, new()와 delete() 호출에 대해 사용자가 정의한 메모리 할당 함수를 지정할 수 있습니다.

이와 같은 기능을 사용할 수 있다면 위 매크로를 참고하여 구현할 수 있어 보입니다.

https://github.com/iFunFactory/engine-plugin-ue4/commit/bc6faababee22025f5fc8b9107e855b0bc769f1e#diff-654564e4578f56d5651644daff28af09476f4a3a70e2a7975a80a3405671e651

위 플러그인의 funapi_std_allocator.h가 비슷한 예시로 참고하실 수 있습니다.

  • Standard Allocator 사용

위 방식 모두 사용하기 어려운 경우 대안으로 MallocAnsi의 사용을 권장 드립니다.

마지막으로 MallocBinned3는 언리얼 엔진 플랫폼에 최적화되어 있고

일반적으로 MallocAnsi보다 더 좋은 성능을 낼 수 있는 것으로 보이지만,

이는 프로젝트에 따라 다르며 정확한 차이를 확인하기 위해서는 언리얼 인사이트를 사용하여 같은 상황에서

프로파일링 하는 것을 권장드립니다.

감사합니다.