stdio


Random ramblings of a anonymous software engineer. Contains occasional profanity. Personal opinions, not related to employer.


마이피플 실행 불가?

주변에 최근에 다음 커뮤니케이션으로 옮긴 사람들이 꽤 있어 마이피플에 (어째서인지 사내 메신져) 대한 이야기를 많이 듣고, 궁금해서 설치를 해보았다.

그런데 맥에서 기동만 하면 죽는 문제가 있어서 결국 사용을 해보지 못했는데, 그 이유를 파고 들어가보니 재미있는 문제.

실제로 죽는 곳은 AIR안에서 죽게 되는데, 마이피플에서 사용중인 AIR 3.9 기준으로 아래와 같다. (주: 디버거 표시와 다르게 정순으로 표기)

  1. 앞 stack frame은 의미가 없으므로 생략
  2. Tamarin JIT Code (symbol-less executable page)
  3. Tamarin JIT Code (symbol-less executable page)
  4. Tamarin JIT Code (symbol-less executable page)
  5. sub_52FF1C __text 000000000052FF1C
  6. sub_345FFE __text 0000000000345FFE
  7. sub_4BBBC6 __text 00000000004BBBC6
  8. sub_4BB942 __text 00000000004BB942
  9. sub_4BAC8A __text 00000000004BAC8A
  10. 0x004BAC8A + B0

실제 크래시 주소는 0x004BAD2D 인데 그 이유는 설정을 가져오는 부분에서, CFArrayGetValueAtIndex에서 가져온건 NULL 체크를 하나, 그 다음에 CFDictionaryGetValue에서 가져온 것을 유효성 체크를 안하고 해당 포인터를 CFStringCompare를 호출하기 때문에 거기서 죽는 Adobe AIR 버그라는 결론. (http://developer.apple.com 문서에 의하면 NULL이 돌아올 수 있는 상황은 분명히 있음에도 불구하고 이렇게 된데에는 아마도 시중에 도는 관련 코드가 대부분 이 체크를 생략하기 때문이 아닐까 생각된다.)

앞에 2번 프레임부터 4번 프레임까지의 내용은 추정으로는 ActionScript 코드 상으로는, MyB.openMainWindow(), Preferences.getItem(), net.daum.myb.services.NativeExtension.startAtLogin() 순으로 추정되는데, 실제로 메모리 덤프를 확인해보지는 않았고, AIR에서 사용하는 Tamarin엔진의 코드 제너레이터 패턴을 본적이 없어서 어디까지나 추정이다. Inlining이 발생하였다면 물론 이 가설은 무효이지만 언듯 본 결과 inlining이 발생할 것 같지는 않다는 소견이다.

OS X 내부에 대해서는 잘 모르는지라 최초에 설정이 NULL로 돌아오는게 OS 버그에 의한건지는 모르겠으나, 일단 돌아온다는건 확실하기 때문에 체크를 해줘야한다는 사실을 이번에 알게 되었다. 아울러 이 버그가 Adobe AIR의 공식 최신 버전인 4.0에도 있다는게 문제. 꽤나 간단한 버그인데, 이 문제를 겪은게 처음이 아니다.

캐논 Selphy 시리즈 프린터 드라이버에도 이 문제가 있다. 해당 문제를 유발하는 ColorPDE.plugin 바이너리를 그대로 재현한 코드는 아래에. 코드 자체가 무의미한 코드가 있는건 컴파일 되기 전 코드가 어째서인지 딱 그렇게 해석이 되어서이지 실수가 아님. 궁극적으로 파보면 같은 문제.

실실적인 원인 NativeApplication.supportsStartAtLogin 또는 NativeApplication.nativeApplication.startAtLogin._setter 둘 중 하나에서 발생을 하게 되는데, 마이피플 입장에서 단기 우회책으로는 이걸 사용하고 있는 net.daum.myb.services.NativeExtension.startAtLogin()에서 flash.system.Capabilities.os를 체크해서 Mac이 포함되어 있을 경우 그냥 return을 하는 방법 정도의 방법 밖에 없다는게 문제일 듯. 결국은 기능을 일시적으로 죽여야하는 우회책. 런타임 문제라 try / catch 같은 것으로도 해결이 안될 것 같지가 않다.

이걸 제대로 해결해야하는 어플리케이션은 꽤나 골치아픈 우회책을 써야 하는데, FRE로 직접 문제가 있는 기능을 구현을 해야하는데 이걸 구현해서 소스를 풀 사람이 있을지는 모르겠다. 어차피 AIR 개발을 안하니 내가 고민할 문제는 아니지만.

다행히도 어도비에서 해당 문제를 해결했으니 다행인데, 어도비 담당자 말로는 출시까지 꽤나 시간이 걸릴것 같다는 이야기.

// Minimized version of the ColorPDE.plugin crasher
// Sangwhan Moon <[email protected]>
//
// Based on ColorPDE.plugin - Copyright (c) Canon Electronics
// Compile with:
// gcc -g -F /Library/Printers/Canon/SELPHYCP/Frameworks \
// -framework SELPHYCPUIKit -framework CoreFoundation colorpdecrasher.c

#include <Carbon/Carbon.h>

#define u kCFPreferencesCurrentUser

int main()
{
    int i, j, k;
    char *p, *q;

    i = GetCountOfLoginItems(u);

    for (j = i; j > 0 ; j--)
    {
        p = ReturnLoginItemPropertyAtIndex(u, 1, j-1);
        q = p;
        k = strcmp("foobar", q);
    }

    return 0;
}