2013-07-31 7 views
1

저는 libwebsockets 라이브러리 (순수 C)를 사용하여 ARMv7 장치에서 실행중인 응용 프로그램 (C++ 11)을 작성하고 있습니다. gcc 4.7.3 (arm, gnueabi) 및 openwrt를 사용하여 툴체인 및 응용 프로그램을 빌드합니다.ARM 장치의 "정의되지 않은 동작"

그래서 서버에 연결하는 동안 libwebsockets 라이브러리는 HTTP 요청 내에서 핸드 셰이크 요청을 보냅니다. 그것은 다음과 같습니다

GET/HTTP/1.1 
Pragma: no-cache 
Cache-Control: no-cache 
Host: 192.168.1.111 
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Key: YDtqt/+y5Efpzo1YiCg5YQ== 
Origin:/
Sec-WebSocket-Protocol: myproto 
Sec-WebSocket-Extensions: deflate-fram 
Sec-WebSocket-Version: 13 

내가 x86_64에 리눅스 (페도라, GCC 4.8.1)에서 내 응용 프로그램을 구축 아니라이 부분 작동합니다. 내가 ARM을위한 응용 프로그램을 구축하고 실행한다면, HTTP 요청은 다음과 같습니다

gPra ma:/HTTP/1.1 
no-<ach 
C chegCon rol 
no<cac�e 
Host: 192.168.1.111 
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Key: QKnxtiEc3IlvyOW254h6kg== 
Origin:/
Sec-WebSocket-Protocol: myproto 
Sec-WebSocket-Extensions: deflate-frame 
Sec-WebSocket-Version: 13 

또는이 (이 때마다 변경) :

GET/HTTP/1.1 
Pragma: no-cache 
Cache-Control: no-cache 
tUpgoade2.168.1.111 
we.soc 

이 애플리케이션의 코드가 정확히 동일 x86_64 리눅스 박스에 관해서는, 그래서 문제는 어딘가에있는 라이브러리 또는 툴체인 (컴파일러, glibc)에있는 것 같아요.

char * 
libwebsockets_generate_client_handshake(struct libwebsocket_context *context, 
    struct libwebsocket *wsi, char *pkt) 
{ 
    char buf[128]; 
    char hash[20]; 
    char key_b64[40]; 
    char *p = pkt; 
    int n; 

    n = libwebsockets_get_random(context, hash, 16); 
    if (n != 16) { 
     lwsl_err("Unable to read from random dev %s\n", 
        SYSTEM_RANDOM_FILEPATH); 
     libwebsocket_close_and_free_session(context, wsi, 
        LWS_CLOSE_STATUS_NOSTATUS); 
     return NULL; 
    } 

    lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64)); 

    p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", 
      lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI)); 

    p += sprintf(p, "Pragma: no-cache\x0d\x0a""Cache-Control: no-cache\x0d\x0a"); 
    p += sprintf(p, "Host: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST)); 
    p += sprintf(p, "Upgrade: websocket\x0d\x0a""Connection: Upgrade\x0d\x0a""Sec-WebSocket-Key: "); 
    strcpy(p, key_b64); 
    p += strlen(key_b64); 
    p += sprintf(p, "\x0d\x0a"); 
    if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) 
     p += sprintf(p, "Origin: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)); 

    if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS)) 
     p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS)); 

    p += sprintf(p, "Sec-WebSocket-Extensions: "); 
    p += sprintf(p, "\x0d\x0a"); 

    if (wsi->ietf_spec_revision) 
     p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a", 
         wsi->ietf_spec_revision); 

    // here my callback is called and I print out the header (see examples above) 
    context->protocols[0].callback(context, wsi, 
     LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, 
     NULL, &p, (pkt + sizeof(context->service_buffer)) - p - 12); 

    p += sprintf(p, "\x0d\x0a"); 
    return p; 
} 

나는 간결에 대한 몇 가지 코드와 주석을 제거했습니다 여기에 (client.c에서) HTTP 요청을 만드는 라이브러리 코드입니다. 글쎄, 난 여기 붙어있어. 모든 것을 망칠 수있는 무언가를 찾을 수 없습니다. 아무도 무슨 일이 일어나고 있는지에 대한 아이디어가 있습니까? 신선한 눈 쌍이 나를 도울 수 있습니다.

감사합니다.

+0

어떻게 당신이'pkt' 메모리를 할당 할 ... 나는 문서 및 ARMv6 이상은 (이상) 정렬되지 않은 액세스를 확인 있어야하는데 오해, 아직 광산은 없습니다, 그래서 YMMV입니다 매개 변수? – Inspired

+0

이 함수는 다른 라이브러리 함수에서 호출되므로 버퍼를 할당하지 않습니다. 'pkt'는 컨텍스트 내부의 struct의 멤버 인 char [4096] 버퍼를 가리 킵니다. – maverik

+1

함수가 호출 될 때까지 컨텍스트가 어떻게 든 할당 해제 될 수 있습니까? 아니면 컨텍스트가 범위를 벗어난 지역 변수입니까? – Inspired

답변

4

ARM 빌드와 조금 비슷해 보이지만 pkt 버퍼 크기가 충분하지 않거나 스택 크기가 충분하지 않을 수 있습니다.

나를 괴롭히는 한 가지 사실은 선언되어 사용되지 않는이 거대한 버프입니다. 실제로 사용되지 않습니까? 아니면 명확성을 위해 제거한 코드 중 일부가 필요합니까? 내가 그런 종류의 것을 보았을 때 버퍼를 오버플로하여 발생하는 정의되지 않은 동작을 방지하기 위해 사용되는 것을 말하면됩니다.

이 코드는 확인되지 않은 sprintfs로 흩어져 있으며 단지 출력 버퍼가 데이터에 충분히 크다고 가정하므로보고있는 것과 같은 이상한 오류가 발생하는 경우가 많습니다.

+0

답변 해 주셔서 감사합니다. 스택 크기를 확인하겠습니다. 'pkt'는'p = (char *) & context-> service_buffer [0]; '이고'service_buffer'는'unsigned char service_buffer [4096]'인'char * p'와 같은 메모리를 가리 킵니다. – maverik

2

동일한 문제 (ARMv6의 libwebsockets에 대한 연결 요청 손상)로 긴 디버깅 세션을 끝냈으므로 다른 사람이 디버깅 2 일 (GDB 사용 방법 학습 포함)을 줄일 수 있습니다.

세 단어 : 정렬되지 않은 메모리 액세스

이상 세 단어 : 실수로 내 메이크 GCC (특히 -mno-정렬되지 않은 액세스) 및 ARMv6 이상 (또는 ARM11 아래 무엇이든)에 대한 권리 컴파일러 플래그를 통과하지 못한 잘못 정렬 된 쓰기 주소보다 1-3 메모리 바이트가 손상됩니다.

편집 : 분명히

관련 문제