2012-10-03 2 views
14

가볍게 넣으려면 작은 메모리 문제가 있으며 원인을 파악하기 위해 도구와 아이디어가 부족합니다.스택 분리 도구 스매싱 버그

4.4.4와 4.7.1 이전에 GCC를 사용하여 최적화 된 컴파일에서 스택 스매싱 문제를 발생시킨 고도의 멀티 스레드 (pthreads) C/C++ 프로그램이 있습니다.

증상은 스레드 중 하나를 생성하는 동안 % RIP뿐 아니라 모든 상위 프레임과 대부분의 레지스터가 0x00 또는 다른 비 감지 주소임을 나타냅니다. 어떤 스레드가 문제를 일으키는지는 겉으로보기에 무작위입니다. 그러나 로그 메시지로 판단 할 경우 동일한 코드 덩어리로 분리 된 것으로 보이며 새로운 스레드를 생성 할 때 반 반복 가능한 시점에있는 것처럼 보입니다.

이로 인해 문제가되는 파일의 print()가 지금까지는 줄이려고 시도 할 때 신뢰할 수없는 것으로 판명 되었기 때문에 문제가되는 코드를 수천 줄의 단일 컴파일 단위보다 좁게 분리하고 격리하는 것이 매우 어려웠습니다. 활성 섹션을 아래로.


extern "C" 
{ 
static ThreadReturnVal ThreadAPI WriterThread(void *act) 
{ 
    Recorder  *rec = reinterpret_cast (act); 
    xuint64  writebytes; 
    LoggerHandle m_logger = XXGetLogger("WriterThread"); 

    if (SetThreadAffinity(rec->m_cpu_mask)) 
    { ... } 
    SetThreadPrio((xint32)rec->m_thread_priority); 

    while (true) 
    { 
    ... poll a ring buffer ... Hard Spin 100% use on a single core, this is that sort of crazy code. 
    } 
} 

내가 디버그 빌드를 시도하지만, 증상, -O2 이상을 빌드 최적화 만 존재 : 결국 스택을 부수고 스레드를 리드

스레드의 생성이다. 내가 Valgrind의/memcheck와 DRD 시도했지만 모두 스택이

A는 -O2 -Wstack 보호기 컴파일 (실패에 도달하고 12 시간의 정도 걸립니다) 날아 전에 어떤 문제를 발견하지 , 아무 잘못 볼 수 없습니다 그러나 -fstack-protector-all을 사용하여 빌드하면 버그로부터 나를 보호 할 수는 있지만 오류는 발생하지 않습니다.

전기 울타리도 트랩되지만 스택이 사라진 후에 만 ​​가능합니다.

질문 : 문제가되는 섹션을 좁히는 데 유용한 다른 도구 나 기술은 무엇입니까?

많은 감사, --Bill

+0

확인. 내가 물지는데 ... 어떤 스택이 부서진거야? –

+1

작성 스레드의 스택 인 경우 일부 코드가 좋을 수도 있습니다. 새 스레드/s에 매개 변수로 무엇을 전달합니까? –

+2

명확성을 위해 g ++ 4.4.2 및 4.8에서 제대로 작동하는지 또는 해당 버전이 테스트되지 않았습니까? –

답변

4

문제는 이런 종류의 접근에 대한 옵션의 몇 :

당신은 손상이 발생하기 전에 스택 주소를 하드웨어 브레이크 포인트 설정을 시도하고 막연하게 유용한 디버깅을 제공하기 위해 손상이 조기에 디버거 나누기를 희망 할 수 상태. 여기서 까다로운 부분은 오른쪽 스택 주소를 선택하는 것입니다. 문제가되는 스레드의 '선택'이 얼마나 무작위인지에 따라 이는 실용적이지 않을 수 있습니다. 그러나 여러분의 의견 중 하나에서 그것은 종종 새로 생성 된 스레드가 박살내는 것처럼 들리므로 이것이 가능할 수도 있습니다. 스레드 생성 중에 중단하고 스레드의 스택 위치를 잡아 당겨서 추측하고 하드웨어 BP를 설정 한 다음 계속하십시오. 너무 일찍, 너무 늦게 또는 전혀하지 않았는지 여부에 따라 오프셋, 헹굼 및 반복을 조정하십시오. 이것은 기본적으로 고급 추측 및 확인이며, 손상 패턴이 너무 무작위 인 경우 크게 방해 받거나 실용적이지 않을 수 있지만, 이것이 반 판독 스택 및 성공적인 디버깅 작업으로 이어지는 빈도가 놀랍습니다.

또 다른 옵션은 크래시 덤프 수집을 시작하는 것입니다.충돌 덤프 사이의 패턴을 찾아보십시오. 그러면 손상 소스에 더 가까이 갈 수 있습니다. 아마도 당신은 운이 좋게 될 것이며, 크래시 덤프 중 하나는 '더 빨리'/ '소스에 더 가깝게'충돌 할 것입니다.

불행히도,이 두 기술은 모두 과학이라는 예술입니다. 그들은 비 결정적이며 운의 건강한 복용량에 의지합니다. (적어도 내 경험으로 말하면, 충돌 덤프로 놀라운 일을 할 수있는 사람들이 있지만, 많은 시간이 걸립니다. 그 수준의 기술을 얻으려면).

다른 메모 : 다른 사람이 지적했듯이 초기화되지 않은 메모리는 디버그와 릴리스의 차이점을 나타내는 매우 일반적인 소스이며 여기에서 쉽게 문제가 될 수 있습니다. 그러나 타이밍에 차이가 있음을 염두에 두어야 할 또 다른 가능성이 있습니다. 스레드가 예약되는 순서와 디버그 순서는 대개 디버그와 릴리스에서 극적으로 다르며 동기화 버그가 하나는 있지만 다른 하나는 가려지지 않을 수 있습니다. 이러한 차이는 단지 실행 속도 차이로 인한 것일 수 있지만, 일부 런타임은 디버그 환경에서 스레드 스케줄링을 의도적으로 엉망으로 생각합니다.

+0

고마워요. 모든 답변과 입력에 대해 답변으로 받아들이고 있습니다.하지만 더 많은 아이디어 나 생각을 갖고 있다면이 버그를 격리하기 위해 계속해서 더 많은 의견을 환영합니다. –

+0

내가 언급 한 것을 잊어 버렸지 만, 코드 기반이 허용하는 경우, 이런 종류의 문제에 유용한 또 다른 속임수가 있습니다. 최대 스레드 수를 변경합니다. 버그를 신뢰할 수있게 repro하는 데 필요한 최소 동시 스레드 수를 확보하면 일반적으로 더 친숙한 디버깅 환경이됩니다. 이상적으로는 두 개의 스레드로 가져올 수 있습니다 (또는 때로는 하나의 스레드로 repros를 발견하고 실제로는 동기화 버그가 아니며 항상 이것을 배제하는 것이 좋습니다). – WeirdlyCheezy

2

당신은 버그의 원인이 될 것입니다, 일부 sutble 오류 발견 된 오류 어쩌면 하나를 확인하는 정적 분석 도구를 사용할 수 있습니다. 이 도구에 대한 정보는 here에서 찾을 수 있습니다.

+0

굿 포인트, 나는 린트 (Lint) 등이이를 찾기 위해 고려하지 않았었다. –

관련 문제