본문 바로가기

SW 지식/DALi와 NUI

CallingConvention Cdecl와 StdCall의 차이

 

최근에 NUI 앱에서 가장 기본 클래스인, View에 TextField 하나를 Add하기만 해도 crash가 발생하며 에뮬레이터에서 앱이 죽는 이슈가 있었습니다.

protected override void OnCreate()
{
    base.OnCreate();

    var window = Window.Instance;
    var layout = new View()
    {
        Layout = new AbsoluteLayout(),
    };
    var textField = new TextField();
    layout.Add(textField);
    window.Add(layout);
}

디버깅 결과, TextChangedCallbackDelegate C# binding에서 죽는다는 것인데 아무런 로그도 잘못 바인딩 된 것도 아니어서 의문을 갖던 차...
(심지어 그 전에는 문제없이 잘 동작하던 기본적인 코드였기 때문에)

C# Binding하는 쪽의 Calling convention field를 바꿔보는 것이 어떻겠냐는 조언이 있었습니다.


(어차피 public github 니까 올려도 되겠지?)

https://github.com/Samsung/TizenFX/pull/5475/files#diff-5514899f2f0aa46519b1e37deedeadbf24adcfb3ece19aeedaa8364677d28376

 

[NUI] Change all CallingConvention to `Cdecl` by Seoyeon2Kim · Pull Request #5475 · Samsung/TizenFX

Description of Change Change all the CallingConvention from Stdcall to Cdecl. stdcall is mainly used for Win32, and there's a default calling convention that cdecl should be used in native C/C++ p...

github.com

-       [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+       [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        private delegate void TextChangedCallbackDelegate(IntPtr textField);

기존 CallingConvention이 StdCall였는데 Cdecl로 바꿨더니 바로 해결되었습니다...!


아래와 같이 PR에 설명은 적었으나, 좀 더 자세히 설명해 보겠습니다.

Change all the CallingConvention from Stdcall to Cdecl.
stdcall is mainly used for Win32, and there's a default calling convention that cdecl should be used in native C/C++ programs. NUI is the C# GUI library, which is binding C++ library.
So, it should use cdecl for the programs. In terms of security, the cdecl convention is "safer" because it is the caller that needs to deallocate the stack.
Hello! Thank you for checking the emulator crash. Normally, the biggest difference in the two calling conventions is who cleans the stack. StdCall is that the callee cleans the stack. On the other hand, Cdecl is that the caller cleans the stack. This enables calling functions with varargs, which makes it appropriate to use for methods that accept a variable number of parameters. (https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.callingconvention?view=net-7.0)

Furthermore, there's a big reason we have to fix these. stdcall is mainly used for Win32, and there's a default calling convention that cdecl should be used in native C/C++ programs. You can see the differences in the pages below !

English) https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 / https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170
Korean) https://m.blog.naver.com/work1989/221275066623

우선 가장 큰 차이는 StdCall은 Callee가 스택을 정리하고, Cdecl은 Caller가 스택을 정리합니다.

이와 관련해서 마이크로소프트 dotnet 가이드에 잘 나와있습니다.

영문) https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.callingconvention?view=net-7.0 

 

CallingConvention Enum (System.Runtime.InteropServices)

Specifies the calling convention required to call methods implemented in unmanaged code.

learn.microsoft.com

한글) https://learn.microsoft.com/ko-kr/dotnet/api/system.runtime.interopservices.callingconvention?view=net-7.0 

 

CallingConvention 열거형 (System.Runtime.InteropServices)

비관리 코드에서 구현된 메서드를 호출하는 데 필요한 호출 규칙을 지정합니다.

learn.microsoft.com

 

또한, `stdcall` 은 주로 Win32에서 사용되고, `cdecl`은 native C/C++ 프로그램에서 사용된다고 합니다. 특히 보안 상으로도 native 프로그램에서는 `cdecl`을 사용하는 것이 더 안전하다고 합니다.

참고) https://m.blog.naver.com/work1989/221275066623

 

__stdcall 과 __cdecl 이 무엇인가?

 코딩을 하다보면 가끔씩 튀어 나오는 녀석들인데 처음에는 호출 규약의  차이? 라고 단순하게 ...

blog.naver.com

 

NUI에서 최신 바이너리에서부터 이와 같은 이슈가 발견된 것은,

기존에 이미 메모리가 깨져있는 문제가 잔존해 있었으나 수면 위로 드러나지 않았는데,
최근 third-party 물리엔진 패치들이 dali-toolkit에 적용되면서
문제 있는 메모리가 사용되는 상황이 되었다.

라는 집단지성의 의견으로 마무리하였습니다.

 

끝~

 

'SW 지식 > DALi와 NUI' 카테고리의 다른 글

DALi (Dynamic Animation Library)  (0) 2021.09.14