범위를 벗어난 배열에 액세스하는 것이 얼마나 위험합니까?


221

범위를 벗어난 어레이에 액세스하는 것이 얼마나 위험합니까 (C)? 때로는 배열 외부에서 읽거나 (이제 프로그램의 다른 부분이나 그 이상으로 사용되는 메모리에 액세스한다는 것을 이해합니다) 또는 배열 외부의 인덱스로 값을 설정하려고합니다. 프로그램이 때때로 충돌하지만 때로는 실행되어 예기치 않은 결과 만 나타납니다.

이제 내가 알고 싶은 것은 이것이 얼마나 위험합니까? 프로그램이 손상되면 그렇게 나쁘지 않습니다. 반면에 완전히 관련이없는 메모리에 액세스 할 수 있기 때문에 프로그램 외부에서 무언가를 깨 뜨리면 매우 나쁩니다. 나는 '모든 일이 일어날 수 있습니다', '세그먼트가 가장 나쁜 문제 일 수 있습니다.' , '하드 디스크가 분홍색으로 변하고 유니콘이 당신의 창 아래에서 노래를 부를 수 있습니다 '를 많이 읽었습니다 .

내 질문 :

  1. 배열 외부에서 값을 읽으면 프로그램 이외의 것이 손상 될 수 있습니까? 나는 물건을 보는 것이 아무것도 변하지 않는다고 상상할 것입니다. 예를 들어 내가 도달 한 파일의 '마지막으로 열린 시간'속성을 변경합니까?
  2. 설정 값이 배열 외부로 빠져 나갈 수 있습니까? 이 스택 오버플로 질문에서 메모리 위치에 액세스 할 수 있으며 안전 보장이 없다는 것을 수집합니다.
  3. 이제 XCode 내에서 작은 프로그램을 실행합니다. 자체 메모리 외부에 도달 할 수없는 프로그램에 대해 추가 보호 기능을 제공합니까? XCode를 해칠 수 있습니까?
  4. 본질적으로 버그가있는 코드를 안전하게 실행하는 방법에 대한 권장 사항이 있습니까?

OSX 10.7, Xcode 4.6을 사용합니다.


일반적으로 OS는 자신과 다른 프로세스를 사용자의 실수로부터 보호합니다. 그래도 꼭 의지하고 싶은 것은 아닙니다.
핫 릭

7
또한 램의 범위를 벗어난 인덱스에 액세스하고 배열 할 때 하드 디스크에있는 파일에 "도달 할 수 없습니다".
DrummerB

1
나는 당신이 C 배열에 대해 묻는다고 생각합니다. 따라서 ObjC와는 아무런 관련이 없으며 실제로 IDE와 관련이 없습니다.
Bryan Chen

17
이상한 결과의 가장 좋아하는 예 는 다음과 같습니다 (스택을 처리하지만 실제로는 깨달았습니다 ...).
phipsgabler

답변:


125

ISO C 표준 (언어의 공식 정의)에 관한 한, 범위를 벗어난 배열에 액세스하는 경우 " 정의되지 않은 동작 "이 있습니다. 문자 그대로의 의미는 다음과 같습니다.

휴대 할 수 없거나 잘못된 프로그램 구조 또는 잘못된 데이터를 사용할 때이 국제 표준에 요구 사항이없는 행동

비표준 메모는 다음과 같이 확장됩니다.

정의되지 않은 동작은 예측할 수없는 결과로 상황을 완전히 무시하는 것, 환경의 특징적인 문서화 된 방식으로 진단 또는 프로그램 실행 중 (진단 메시지 발행 여부에 관계없이), 번역 또는 실행 종료 (발급 포함)에 이르기까지 다양합니다. 진단 메시지).

이것이 이론입니다. 현실은 무엇입니까?

"최상의"경우 현재 실행중인 프로그램이 소유하고 있거나 (프로그램이 오작동 할 수 있음) 현재 실행중인 프로그램이 소유 하지 않은 메모리에 액세스 할 수 있습니다 (아마도 프로그램이 세그먼테이션 오류와 같은 것으로 충돌). 또는 프로그램이 소유 한 메모리에 쓰려고 시도 할 수 있지만 읽기 전용으로 표시되어 있습니다. 이로 인해 프로그램이 중단 될 수도 있습니다.

그것은 프로그램이 서로 동시에 실행중인 프로세스를 보호하려고 시도하는 운영 체제에서 실행되고 있다고 가정합니다. 코드가 "베어 메탈 (bare metal)"에서 실행중인 경우, OS 커널 또는 임베디드 시스템의 일부인 경우 그러한 보호 기능이 없습니다. 오작동하는 코드는 그러한 보호 기능을 제공하는 것입니다. 이 경우 하드웨어 (또는 주변 사물 또는 사람)에 대한 물리적 손상을 포함하여 손상 가능성이 훨씬 더 큽니다.

보호 된 OS 환경에서도 항상 100 % 보호되는 것은 아닙니다. 예를 들어 권한이없는 프로그램이 루트 (관리) 액세스를 얻을 수있게하는 운영 체제 버그가 있습니다. 일반 사용자 권한이 있어도 오작동하는 프로그램은 과도한 리소스 (CPU, 메모리, 디스크)를 소비하여 전체 시스템을 중단시킬 수 있습니다. 많은 맬웨어 (바이러스 등)가 버퍼 오버런을 악용하여 시스템에 대한 무단 액세스를 얻습니다.

(역사적 예 : 코어 메모리 가있는 일부 구형 시스템 에서 타이트한 루프로 단일 메모리 위치에 반복적으로 액세스하면 문자 그대로 해당 메모리 덩어리가 녹을 수 있습니다. 다른 방법으로는 CRT 디스플레이 파괴 및 판독 이동 등이 있습니다 / 드라이브 캐비닛의 고조파 주파수로 디스크 드라이브의 헤드를 쓰면 테이블을 가로 질러 바닥으로 떨어집니다.)

그리고 항상 걱정할 Skynet 이 있습니다.

결론은 이것입니다. 의도적으로 나쁜 일을하는 프로그램을 작성할 수 있다면 적어도 이론적으로 버그가있는 프로그램이 우연히 같은 일을 할 수 있다는 것 입니다.

실제로, 그건 매우 맥 OS X 시스템에서 실행되는 버그 프로그램이 충돌보다 더 심각한 아무것도 할 것입니다 가능성. 그러나 버그가있는 코드가 실제로 나쁜 일을하는 것을 완전히 막을 수는 없습니다 .


1
고마워, 나는 이것을 완전히 이해한다. 그러나 즉시 후속 질문을 시작합니다. 초보 프로그래머가 자신의 끔찍한 창조물로부터 컴퓨터를 보호하기 위해 무엇을 할 수 있습니까? 프로그램을 철저히 테스트 한 후 전 세계에서 활용할 수 있습니다. 그러나 첫 번째 시운전은 잘못된 프로그램입니다. 여러분은 시스템을 어떻게 자신으로부터 안전하게 보호합니까?
ChrisD

6
@ChrisD : 우리는 운이 좋은 경향이 있습니다. 8-)} 요즘 OS 수준의 보호 기능은 꽤 좋습니다. 최악의 경우, 실수로 포크 폭탄을 작성하면 복구하기 위해 재부팅해야 할 수도 있습니다. 그러나 프로그램이 위험한 상황에서 무언가를 시도하지 않는 한 시스템에 대한 실제 피해는 걱정할 가치가 없습니다. 정말로 걱정된다면 가상 머신에서 프로그램을 실행하는 것은 나쁜 생각이 아닙니다.
Keith Thompson

1
반면에, 내가 사용한 컴퓨터에서 많은 이상한 일들이 발생하는 것을 보았습니다 (파일이 손상되거나 복구 할 수없는 시스템 오류 등). 나는 C 프로그램 전시로 인해 얼마나 많은 것들이 발생했는지 모릅니다. 두려운 정의되지 않은 행동. (지금까지 실제 악마는 코
Keith Thompson

1
나에게 포크 폭탄을 가르쳐 주셔서 감사합니다-재귀를 파악하려고 할 때, 그것에 가까운 일을했습니다 :)
ChrisD

2
scientificamerican.com/article/… 그래서 현대 전자 제품에서는 여전히 화재가 발생할 수 있습니다.
Mooing Duck

25

일반적으로 오늘날 운영 체제 (일반적으로 인기있는 운영 체제)는 가상 메모리 관리자를 사용하여 보호 된 메모리 영역의 모든 응용 프로그램을 실행합니다. 프로세스에 할당 / 할당 된 영역 외부의 REAL 공간에있는 위치를 단순히 읽거나 쓰는 것이 그리 쉬운 일이 아님이 밝혀졌습니다.

직접 답변 :

1) 읽기는 다른 프로세스를 거의 직접 손상시키지 않지만 프로그램 / 프로세스를 암호화, 암호 해독 또는 유효성 검사하는 데 사용되는 KEY 값을 읽으면 프로세스를 간접적으로 손상시킬 수 있습니다. 읽은 데이터를 기반으로 의사 결정을 내리는 경우 경계를 벗어나면 코드에 악영향을 줄 수 있습니다.

2) 메모리 주소로 액세스 할 수있는 로션에 쓰면 실제로 무언가를 손상시킬 수있는 유일한 방법은 쓰려는 메모리 주소가 실제로 하드웨어 레지스터 (실제로 데이터 저장이 아니라 일부 부분을 제어하기위한 위치) 인 경우입니다. RAM 위치가 아님). 사실, 다시 쓸 수없는 (또는 그 성격의) 프로그램 가능한 위치를 한 번 작성하지 않는 한 여전히 정상적으로 무언가를 손상시키지 않습니다.

3) 일반적으로 디버거 내에서 실행하면 코드가 디버그 모드로 실행됩니다. 디버그 모드에서 실행하면 실습 또는 불법으로 간주되는 작업을 수행했을 때 코드를 더 빨리 중지하지 않습니다.

4) 매크로를 사용하지 말고 이미 내장 된 배열 인덱스 바운드 검사가있는 데이터 구조 등을 사용하십시오.

추가 위의 정보는 실제로 메모리 보호 창이있는 운영 체제를 사용하는 시스템에만 해당됩니다. 내장 시스템 또는 메모리 보호 창 (또는 가상 주소 지정 창)이없는 운영 체제 (실시간 또는 기타)를 사용하는 시스템의 코드를 작성하는 경우 메모리를 읽고 쓰는 데 훨씬 더주의를 기울여야합니다. 이러한 경우에도 보안 문제를 피하기 위해 항상 SAFE 및 SECURE 코딩 방법을 사용해야합니다.


4
안전하고 안전한 코딩 방법이 항상 사용 되어야합니다 .
Nik Bougalis

3
매우 구체적인 예외를 잡아서 복구하는 방법을 모르는 경우 버그 코드에 try / catch를 사용하지 않는 것이 좋습니다. Catch (...)는 버그가있는 코드에 추가 할 수있는 최악의 방법입니다.
유진

1
@NikBougalis-나는 완전히 동의하지만 OS에 메모리 보호 / 가상 주소 공간이 포함되어 있지 않거나 OS가없는 경우 더 중요합니다 :-)
trumpetlicks

@ 유진-나는 나에게 문제가되는 것을 눈치 채지 못했지만, 나는 당신에게 동의하고, 그것을 편집
했습니까

1) 당신은 내가 비밀을 유지해야 할 것을 드러 낼 것이기 때문에 피해를 의미합니까? 2) 무슨 뜻인지 모르겠지만 배열 범위 밖의 위치에 액세스하려고하면 RAM에만 액세스한다고 생각합니까?
ChrisD

9

경계를 확인하지 않으면 보안 허점을 포함하여 추악한 부작용이 발생할 수 있습니다. 못생긴 것 중 하나는 임의의 코드 실행 입니다. 전형적인 예 : 고정 크기 배열 strcpy()이 있고 사용자가 제공 한 문자열을 거기에 넣는 데 사용 하는 경우 사용자는 버퍼를 오버플로하고 함수가있을 때 CPU가 반환 해야하는 코드 주소를 포함하여 다른 메모리 위치를 덮어 쓰는 문자열을 제공 할 수 있습니다 마무리합니다.

즉, 사용자가 프로그램을 본질적으로 호출하게하는 문자열을 보낼 수 있습니다.이 경우 프로그램이 exec("/bin/sh")셸로 전환되어 모든 데이터 수집 및 머신을 봇넷 노드로 전환하는 등 시스템에서 원하는 모든 것을 실행합니다.

이 작업을 수행하는 방법에 대한 자세한 내용은 재미와 이익을 위해 스택 스매싱을 참조하십시오 .


그 점을 강화 해 주셔서 감사합니다. 범위를 넘어 배열 요소에 액세스해서는 안된다는 것을 알고 있습니다. 그러나 문제는 내 프로그램에 모든 종류의 해를 끼치는 것 외에 실수로 내 프로그램의 메모리를 넘어서도 도달 할 수 있는가하는 것입니다. 그리고 나는 OSX를 의미합니다.
ChrisD

@ChrisD : OS X는 최신 운영 체제이므로 완전한 메모리 보호 기능을 제공합니다. 예를 들어, 프로그램이 수행 할 수있는 작업으로 제한되어서는 안됩니다. 루트 권한으로 실행하지 않는 한 다른 프로세스와의 혼란을 포함해서는 안됩니다.
che

오히려 루트 권한이 아닌 링 0 권한으로 말하고 싶습니다.
Ruslan

더 흥미로운는 하이퍼 현대 컴파일러는 코드 시도가 읽을 경우 결정할 수있다 foo[0]을 통해 foo[len-1]이전의 수표를 사용 한 후 len실행하거나 코드 조각을 건너 하나에 배열의 길이에 대해, 컴파일러도 무조건 다른 코드를 실행 주시기한다 응용 프로그램이 스토리지를 지나서 스토리지를 소유하고 있으며 읽기 효과는 좋지만 다른 코드를 호출하면 효과가 없습니다.
supercat 2016 년

8

당신은 쓰기:

나는 '무엇이 일어날 수 있는가', '세그먼트가 가장 나쁜 문제일지도 모른다', '하드 디스크가 분홍색으로 변하고 유니콘이 당신의 창 아래에서 노래를 부르고있을 수 있습니다'를 많이 읽었습니다.

총을 넣으십시오. 특정 조준 및 발사없이 창 밖으로 지적하십시오. 위험은 무엇입니까?

문제는 당신이 모르는 것입니다. 코드가 프로그램과 충돌하는 것을 덮어 쓰면 정의 된 상태로 중지되기 때문에 괜찮습니다. 그러나 충돌하지 않으면 문제가 발생하기 시작합니다. 프로그램을 관리하는 리소스는 무엇이며 어떻게 할 수 있습니까? 프로그램을 제어 할 수있는 리소스는 무엇이며 어떻게 할 수 있습니까? 이러한 오버플로로 인해 발생한 적어도 하나의 주요 문제를 알고 있습니다. 이 문제는 프로덕션 데이터베이스에 대한 관련이없는 변환 표를 엉망으로 만드는 의미없는 통계 함수에있었습니다. 그 결과 결과적으로 매우 비싼 정리가 이루어졌습니다. 실제로이 문제가 하드 디스크를 포맷했을 경우 훨씬 저렴하고 다루기 쉬울 것입니다.

운영 체제가 사용자를 보호한다는 아이디어는 낙관적입니다. 가능하면 경계를 쓰지 않도록하십시오.


좋아, 이것은 내가 두려워했던 바로 그 것이었다. 나는 '경계를 쓰지 않기 위해 노력할 것입니다.'하지만 지난 몇 개월 동안 내가 한 일을 보면서 분명히 많은 일을 할 것입니다. 안전한 연습 방법없이 프로그래밍을 어떻게 잘 했습니까?
ChrisD

3
안전하다고 누가 말
했는지

7

루트 또는 다른 권한있는 사용자로 프로그램을 실행하지 않으면 시스템에 아무런 영향을 미치지 않으므로 일반적으로 이것이 좋습니다.

임의의 메모리 위치에 데이터를 쓰면 각 프로세스가 자체 메모리 공간에서 실행될 때 컴퓨터에서 실행중인 다른 프로그램을 직접 "손상"시키지 않습니다.

프로세스에 할당되지 않은 메모리에 액세스하려고하면 운영 체제가 세그먼트 오류로 인해 프로그램 실행을 중지합니다.

따라서 루트로 실행하지 않고 / dev / mem과 같은 파일에 직접 액세스하지 않고도 프로그램이 운영 체제에서 실행중인 다른 프로그램을 방해 할 위험이 없습니다.

그럼에도 불구하고 우연히 임의의 데이터를 임의의 메모리 위치에 맹목적으로 쓰면 손상 될 수있는 모든 것을 손상시킬 수 있습니다.

예를 들어, 프로그램은 프로그램 어딘가에 저장된 파일 이름으로 지정된 특정 파일을 삭제하려고 할 수 있습니다. 실수로 파일 이름이 저장된 위치를 덮어 쓰면 대신 다른 파일을 삭제할 수 있습니다.


1
당신이하면 되는 루트 (또는 다른 권한있는 사용자)로 실행,하지만 조심. 버퍼 및 어레이 오버런은 일반적인 맬웨어 악용입니다.
John Bode

실제로 모든 일일 컴퓨팅에 사용하는 계정은 관리자 계정이 아닙니다 (시스템이므로 OSX 용어를 사용합니다). 메모리 위치를 설정하여 무언가를 손상시킬 수 없다고 말 하시겠습니까? 실제로 좋은 소식입니다!
ChrisD

우연히 해칠 수있는 최악의 피해 이전에 이미 언급했듯이 사용자가 할 수있는 최악의 피해입니다. 100 % 확실하게 데이터를 삭제하지 않으려면 컴퓨터에 다른 계정을 추가하고 실험 해 볼 수 있습니다.
mikyra

1
@mikyra : 시스템의 보호 메커니즘이 100 % 효과적 일 경우에만 해당됩니다. 멀웨어가 있으면 항상 그에 의존 할 수는 없습니다. (나는 그것이 걱정할만한 가치가 있다고 제안하고 싶지 않다; 가능하지만, 프로그램이 실수 로 맬웨어에 의해 악용 된 것과 동일한 보안 허점을 악용 할 수는 없다 .)
Keith Thompson

1
신뢰할 수없는 출처의 코드 실행 원하는 네트워크 연결을 할 수없는 경우 방화벽의 상태를 읽거나 완전히 종료하지 않고 방화벽 팝업에서 확인 버튼을 클릭하기 만하면됩니다. 모호한 소스의 최신 해킹으로 바이너리 패치. 주인이 양팔과 강도 높은 강화 문을 활짝 열어 둔 상태에서 도난을 자발적으로 초대하는 것은 금고의 잘못이 아닙니다.
mikyra

4

NSArrayObjective-C의 s에는 특정 메모리 블록이 지정됩니다. 어레이의 경계를 초과하면 어레이에 할당되지 않은 메모리에 액세스하고 있음을 의미합니다. 이것은 다음을 의미합니다.

  1. 이 메모리는 어떤 값이든 가질 수 있습니다. 데이터 유형에 따라 데이터가 유효한지 알 수있는 방법이 없습니다.
  2. 이 메모리에는 개인 키 또는 다른 사용자 자격 증명과 같은 민감한 정보가 포함될 수 있습니다.
  3. 메모리 주소가 유효하지 않거나 보호되어있을 수 있습니다.
  4. 메모리는 다른 프로그램이나 스레드가 액세스하기 때문에 값을 변경할 수 있습니다.
  5. 다른 것들은 메모리 매핑 된 포트와 같은 메모리 주소 공간을 사용합니다.
  6. 알 수없는 메모리 주소에 데이터를 쓰면 프로그램이 중단되고 OS 메모리 공간을 덮어 쓰며 일반적으로 햇빛이 lo 수 있습니다.

프로그램의 측면에서 코드가 배열의 범위를 초과하는 경우를 항상 알고 싶습니다. 이로 인해 알 수없는 값이 반환되어 응용 프로그램이 중단되거나 유효하지 않은 데이터가 제공 될 수 있습니다.


NSArrays범위를 벗어난 예외가 있습니다. 그리고이 질문은 C 배열에 관한 것 같습니다.
DrummerB

실제로 C 배열을 의미했습니다. NSArray가 있다는 것을 알고 있습니다.하지만 지금은 대부분의 연습이 C에 있습니다.
ChrisD

4

코드를 테스트 할 때 Valgrind에서이memcheck 도구 를 사용해보십시오 . 스택 프레임 내에서 개별 배열 경계 위반을 포착하지는 않지만 미묘하고 넓게 만드는 것을 포함하여 많은 다른 종류의 메모리 문제를 포착해야합니다. 단일 기능의 범위를 벗어난 문제.

매뉴얼에서 :

Memcheck는 메모리 오류 감지기입니다. C 및 C ++ 프로그램에서 일반적인 다음과 같은 문제점을 발견 할 수 있습니다.

  • 메모리에 액세스하면 (예 : 힙 블록 오버런 및 언더런 실행, 스택의 상단 오버런 및 메모리가 해제 된 후의 메모리 액세스)해서는 안됩니다.
  • 정의되지 않은 값, 즉 초기화되지 않았거나 다른 정의되지 않은 값에서 파생 된 값 사용
  • 이중 해제 힙 블록과 같은 힙 메모리 해제 또는 malloc / new / new [] 대 사용 가능 / 삭제 / 삭제 []의 일치하지 않는 사용
  • memcpy 및 관련 함수에서 src 및 dst 포인터가 겹칩니다.
  • 메모리 누수가 발생합니다.

ETA : Kaz의 답변에 따르면, 만병 통치약은 아니며 특히 흥미로운 액세스 패턴을 사용할 때 항상 가장 유용한 결과를 제공하지는 않습니다 .


XCode 분석기가 그 대부분을 찾을 것이라고 생각합니까? 그리고 내 질문은 이러한 버그를 찾는 방법이별로 없지만 여전히 버그가있는 프로그램을 실행하는 것이 내 프로그램에 할당되지 않은 메모리에 위험한 경우입니다. 버그가 발생
했는지

3

시스템 레벨 프로그래밍 또는 임베디드 시스템 프로그래밍을 수행하는 경우 임의의 메모리 위치에 쓰면 매우 나쁜 일이 발생할 수 있습니다. 구형 시스템과 많은 마이크로 컨트롤러는 메모리 매핑 된 IO를 사용하므로 주변 장치 레지스터에 매핑되는 메모리 위치에 쓰는 것이 특히 비동기식으로 수행되는 경우 혼란을 초래할 수 있습니다.

플래시 메모리 프로그래밍이 그 예입니다. 메모리 칩의 프로그래밍 모드는 칩의 주소 범위 내의 특정 위치에 특정 값 시퀀스를 기록하여 활성화됩니다. 진행 중 칩의 다른 위치에 다른 프로세스를 쓰려면 프로그래밍주기가 실패합니다.

어떤 경우에는 하드웨어가 주소를 둘러싸고 (가장 중요한 비트 / 바이트 주소는 무시 됨) 실제 주소 공간 끝을 넘어 주소에 쓰면 실제로 데이터가 바로 기록됩니다.

마지막으로, MC68000과 같은 구형 CPU는 하드웨어 재설정만으로 다시 갈 수있는 수준까지 잠글 수 있습니다. 수십 년 동안 그들에 대해 작업하지 않았지만 예외를 처리하려고 할 때 버스 오류 (존재하지 않는 메모리)가 발생했을 때 하드웨어 재설정이 주장 될 때까지 중단 될 것이라고 생각합니다.

가장 큰 권장 사항은 제품에 대한 명백한 플러그이지만 개인적 관심은 없으며 어떤 방식으로도 관련이 없습니다. 그러나 수십 년의 C 프로그래밍 및 신뢰성이 중요한 임베디드 시스템을 기반으로 Gimpel의 PC Lint는 이러한 종류의 오류를 감지 할뿐만 아니라 나쁜 습관에 대해 끊임없이 당신을 괴롭힘 으로써 더 나은 C / C ++ 프로그래머를 만들 것입니다 .

또한 누군가의 사본을 걸 수있는 경우 MISRA C 코딩 표준을 읽는 것이 좋습니다. 나는 최근의 것들을 보지 못했지만 예전에는 그들이 당신이 그들이 다루는 일을하지 않아야하는 이유에 대해 잘 설명했습니다.

Dunno는 당신에 대해 있지만 두 번째 또는 세 번째 시간에 응용 프로그램에서 코어 덤프 또는 전화 끊기를 얻습니다. 어떤 회사에서 생산했는지에 대한 내 의견은 절반으로 줄어 듭니다. 4 번째 또는 5 번째와 패키지가 선반웨어가되면서 패키지 / 디스크의 중심을 통해 나무 기둥을 몰아내어 다시는 나를 괴롭히지 않도록했습니다.


시스템에 따라 범위를 벗어난 읽기 는 예측할 수없는 동작을 트리거 할 수도 있고 범위를 벗어난로드에서 양성 하드웨어 동작이 양성 컴파일러 동작을 의미하지는 않지만 양성일 수도 있습니다.
supercat 2016 년

2

C 코드에서 배열의 끝 부분에 액세스하는 코드를 의도적으로 생성하는 DSP 칩 용 컴파일러로 작업하고 있습니다.

반복의 끝이 다음 반복을 위해 일부 데이터를 프리 페치하도록 루프가 구성되어 있기 때문입니다. 따라서 마지막 반복이 끝날 때 프리 페치 된 데이텀은 실제로 사용되지 않습니다.

이와 같은 C 코드를 작성하면 정의되지 않은 동작이 발생하지만 이는 최대 이식성과 관련된 표준 문서의 형식 일뿐입니다.

더 자주, 그렇지 않은 경우, 범위를 벗어나는 프로그램은 영리하게 최적화되지 않습니다. 그것은 단순히 버그입니다. 이 코드는 가비지 값을 가져오고 앞에서 언급 한 컴파일러의 최적화 된 루프와 달리 이후 계산에서이 값 을 사용 하여 결과를 손상시킵니다.

이와 같은 버그를 잡는 것이 가치가 있으며, 그 이유만으로도 동작을 정의하지 않아도됩니다. 즉, 런타임이 "main.c의 42 행에서 배열 오버런"과 같은 진단 메시지를 생성 할 수 있습니다.

가상 메모리가있는 시스템에서는 다음에 오는 주소가 매핑되지 않은 가상 메모리 영역에 있도록 배열이 할당 될 수 있습니다. 그러면 액세스가 프로그램을 폭격합니다.

따로, C에서는 배열의 끝을 지나는 포인터를 만들 수 있습니다. 그리고이 포인터는 배열의 내부에 대한 포인터보다 크게 비교해야합니다. 이것은 C 구현이 메모리의 끝에 배열을 배치 할 수 없다는 것을 의미합니다. 하나의 더하기 주소가 배열의 다른 주소보다 줄어든 것처럼 보입니다.

그럼에도 불구하고, 초기화되지 않았거나 범위를 벗어난 값에 액세스하는 것은 최대로 이식 가능하지 않더라도 때때로 유효한 최적화 기술입니다. 이는 예를 들어 Valgrind 도구가 액세스가 발생할 때 초기화되지 않은 데이터에 대한 액세스를보고하지 않고 나중에 프로그램의 결과에 영향을 줄 수있는 방식으로 값이 사용되는 경우에만 발생합니다. "xxx : nnn의 조건부 분기는 초기화되지 않은 값에 따라 다릅니다"와 같은 진단을받으며 원래 위치를 추적하기가 어려운 경우가 있습니다. 이러한 모든 액세스가 즉시 갇히게되면 컴파일러 최적화 코드와 올바르게 수동 최적화 된 코드에서 발생하는 많은 오 탐지가 발생합니다.

말하자면, Linux로 포팅하고 Valgrind에서 실행될 때 이러한 오류를 발생시키는 공급 업체의 일부 코덱으로 작업하고있었습니다. 그러나 공급 업체는 몇 비트실제로 사용되는 값 중 하나는 초기화되지 않은 메모리에서 왔으며 해당 비트는 논리에 의해 신중하게 피했습니다. 값의 올바른 비트 만 사용되었으며 Valgrind는 개별 비트를 추적 할 수 없습니다. 초기화되지 않은 자료는 인코딩 된 데이터의 비트 스트림 끝을지나 단어를 읽었을 때 발생했지만 코드는 스트림에 몇 비트가 있는지 알고 실제로 실제보다 많은 비트를 사용하지 않습니다. 비트 스트림 배열의 끝을 넘어서 액세스해도 DSP 아키텍처에 아무런 해를 끼치 지 않기 때문에 (어레이 다음에는 가상 메모리가없고, 메모리 매핑 된 포트가없고, 주소가 랩핑되지 않습니다) 유효한 최적화 기술입니다.

ISO C에 따르면 단순히 C 표준에 정의되지 않은 헤더를 포함하거나 프로그램 자체 또는 C 표준에 정의되지 않은 함수를 호출하는 것은 정의되지 않은 예이므로 "정의되지 않은 동작"은 실제로 의미가 없습니다. 행동. 정의되지 않은 동작은 "지구상의 누군가가 정의하지 않음", "ISO C 표준에 의해 정의되지 않음"을 의미하지 않습니다. 그러나 물론, 때로는 정의되지 않은 동작이 정말 됩니다 절대적으로 누군가에 의해 정의되어 있지 않습니다.


또한, 표준에 명시된 모든 구현 제한에 명목상으로 세금을 부과하더라도 특정 구현이 올바르게 처리하는 프로그램이 하나 이상있는 경우 해당 위반은 구속력이없는 다른 프로그램을 제공 할 때 임의로 구현 될 수 있습니다. 준수 " 따라서 C 프로그램 (플랫폼의 "하나의 프로그램"이외의 다른 프로그램)의 99.999 %는 표준에 요구 사항이없는 행동에 의존합니다.
supercat

1

자신의 프로그램 외에도, 나는 당신이 아무것도 깨뜨릴 것이라고 생각하지 않습니다. 최악의 경우 커널이 당신의 프로세스에 할당하지 않은 페이지에 해당하는 메모리 주소를 읽거나 쓰려고 시도하여 적절한 예외를 생성합니다 그리고 살해당하는 것입니다.


3
..뭐? 나중에 사용되는 일부 변수를 저장하는 데 사용되는 자체 프로세스에서 메모리를 덮어 쓰는 것은 어떻습니까? 그 버그는 추적하기에 많은 즐거움입니다. segfault가 가장 좋은 결과입니다. -1
Ed S.

2
나는 그가 자신의 프로그램 외에 다른 프로세스를 "중단하지"않을 것이라는 것을 의미한다;)
jbgs

나는 내 자신의 프로그램을 중단해도 상관 없다. 나는 단지 배우고 있습니다. 어쨌든 배열의 범위를 벗어난 것에 액세스하면 프로그램이 잘못되었습니다. 내 작품을 디버깅하는 동안 다른 것을 깨뜨릴 위험에 대해 점점 더 걱정하고 있습니다.
ChrisD

문제는 : 나에게 할당되지 않은 메모리에 액세스하려고하면 프로세스가 종료 될 것임을 확신 할 수 있습니까? (OSX에 있음)
ChrisD

3
몇 년 전 저는 서투른 C 프로그래머였습니다. 나는 수백 번 그들의 경계 밖의 배열에 접근했습니다. 운영 체제에서 프로세스를 종료하는 것 외에는 아무 일도 일어나지 않았습니다.
jbgs
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.