2016-07-10 2 views
3

현재 C/C++에서 작은 VM을 작성 중입니다. 분명히 사용자가 null 포인터를 역 참조하는 경우 전체 VM 충돌을 허용 할 수 없기 때문에 VM이 커지고 더 많은 시스템이 구현됨에 따라 성가신되고있는 모든 액세스를 확인해야합니다.signal.h는 널 포인터를 잡을 수있는 확실한 방법입니까?

그래서 나는 생각했다 : sigsegv에 대한 신호 처리기를 작성하고 운영 체제가 그 일을하지만 프로그램을 종료하는 대신 VM 예외 처리기를 호출하게하십시오.

(내 아주 간단한 테스트 케이스로) 작동하는 것처럼 보이지만, null-derefs에 던져지는 Sigsegv 나 OS 생성 신호에 대해 호출되는 핸들러를 보장하지 못했습니다.

내 질문은 :현대 destkop OSH에서 signal.h를 믿을 수 있습니까 (표준이 아닌 경우 linux/win 이외의 다른 제품에서 작동하지 않아도 상관하지 않음 : pet 프로젝트 임) . 신호 (...) 또는 longjmp (...)의 모호한 제한 사항을 알고 있어야합니다.)

고맙습니다!

/* ... */ 

jmp_buf env; 

/* ... */ 

void handler(int) { 
    longjmp(env, VM_NULLPTR); 
} 

/* ... */ 

if(setjmp(env)) { 
    return vm_throw("NullPtrException"); 
} 
switch(opcode) { 

    /* instructions */ 

    case INVOKE: 
     *stack_top = vm_call(stack_top->obj); // don't check anything in the case where stack_top or stack_top->obj is null handler() will be called an a "NullPtrException" will be thrown 
    break; 

    /* more instructions */ 

} 

/* ... */ 

참고 : 여기에

는 의사의 구현 난 단지, 쓰레기 (매달려) 포인터는 GC에 의해 처리됩니다 널 (null)를 확인해야하고 일이 안된다.

+0

null 포인터를 역 참조하는 것 외에도 코드는 가비지 포인터 또는 다른 종류의 잘못된 포인터를 역 참조 할 수도 있습니다. 반드시 신호를 생성하지는 않습니다. 따라서 모든 포인터 액세스의 유효성을 검증 할 수있는 대안은 없습니다. –

+0

포인터 디 레퍼런스를 호스트 OS에 전달하는 경우 VM이 아닙니다. 기껏해야 에뮬레이션 래퍼입니다 (하지만 와인은 그게 무엇인지 알려주지 않습니다!). –

+0

@Sam Varshavchik : 이것이 바로 마지막 메모가있는 이유입니다. 쓰레기는 절대 일어나지 않아야합니다. –

답변

1

난 당신이 내 헤더 및 기능은 모든 표준 호환 시스템에 사용할 수 있다는 점에서 믿을 수있는 현대 destkop의 운영체제

에 signal.h에 의지 할 수 있습니다. 그러나 정확히 어떤 신호가 던져지며 언제 OS간에 일관성이 없는지.

Windows에서 세그먼트 결함을 발생 시키려면 시스템을 cygwin 또는 유사한 환경으로 컴파일해야 할 수 있습니다. Visual Studio로 컴파일 된 프로그램은 "structured exceptions"을 사용하여 잘못된 저장 장치 액세스를 처리합니다.


는 널 포인터를 잡을 수있는 신뢰할 수있는 방법 signal.h인가?

null 포인터 역 참조로 인해 POSIX 시스템에서도 세그먼트 화 오류 신호가 발생하지 않는 경우가 있습니다.

  • 경우에 따라 데이터 멤버에 액세스하지 않는 멤버 함수를 호출하기 위해 null 포인터를 역 참조하는 경우와 같이 일반적으로 컴파일러가 작업을 최적화하는 경우가 있습니다. 유효하지 않은 메모리 액세스가 없으면 신호도 없습니다. 물론이 경우에도 충돌이 발생하지 않습니다.
  • 실제로 주소 0이 실제로 유효 할 수도 있습니다. AIX에서 그렇습니다. 걱정하지 않아도됩니다. 또한 리눅스에 관해서는 신경 쓰지 만 기본값은 아니며 케이스가 어디에 있는지 신경 쓰지 않을 수도 있습니다. 자세한 내용은 this answer을 참조하십시오.

그런 다음 신호 처리기의 구현이있다. longjmp은 비동기 신호 안전이 아니므로 다른 안전하지 않은 작업이 수행되는 동안 신호가 발생하면 중단 된 작업으로 인해 프로그램이 일관성없는 상태로 남아있을 수 있습니다. 자세한 내용은 John Zwinck의 answerlibc documentation의 내용을 참조하십시오.

+0

고맙습니다. 그게 내가 찾고 있던거야! –

2

신호 처리기에서 longjmp() 호출은 신호 처리기가 비동기 신호 안전하지 않은 코드에서 호출되지 않는 경우에만 안전합니다. 예를 들어, printf() 패밀리 중 하나에 불량 포인터를 전달하여 SIGSEGV를 수신하는 경우 신호 처리기에서 longjmp()을 사용할 수 없습니다.

+0

나는 핸들러 함수가 (undef-behavior를 가지고 있기 때문에) 리턴해서는 안된다는 것을 읽었다. 이것은 내가 printf의 호출을 손으로 위생적으로해야한다는 것을 의미합니까? C++ 입출력에서도 그렇습니까? –

+0

printf뿐만 아니라 http://man7.org/linux/man-pages/man7/signal.7.html에 명시 적으로 나열되지 않은 표준 라이브러리 함수입니다. 네, C 함수를 사용하여 구현 된 C++ I/O를 포함하며 I/O 이상을 포함합니다 (또 한 가지 예를 들면'mktime()'을 사용할 수 없습니다). –

관련 문제