우리는 정확성이 주어진 것처럼 매일 컴파일러를 사용하지만 컴파일러도 프로그램이며 잠재적으로 버그를 포함 할 수 있습니다. 나는 항상이 완벽한 견고성에 대해 궁금했다. 컴파일러 자체에 버그가 발생한 적이 있습니까? 이것이 무엇이며 컴파일러 자체에 문제가 있다는 것을 어떻게 알았습니까?
... 어떻게 합니까 그들은 컴파일러 그렇게 신뢰성을?
우리는 정확성이 주어진 것처럼 매일 컴파일러를 사용하지만 컴파일러도 프로그램이며 잠재적으로 버그를 포함 할 수 있습니다. 나는 항상이 완벽한 견고성에 대해 궁금했다. 컴파일러 자체에 버그가 발생한 적이 있습니까? 이것이 무엇이며 컴파일러 자체에 문제가 있다는 것을 어떻게 알았습니까?
... 어떻게 합니까 그들은 컴파일러 그렇게 신뢰성을?
답변:
시간이 지남에 따라 수천 명 또는 수백만 명의 개발자가 사용량을 통해 철저히 테스트합니다.
또한 해결해야 할 문제는 매우 상세한 기술 사양에 의해 잘 정의되어 있습니다. 또한 작업의 특성상 단위 / 시스템 테스트에 쉽게 적합합니다. 즉, 기본적으로 텍스트 입력을 매우 특정한 형식으로 변환하여 다른 종류의 잘 정의 된 형식 (일부 바이트 코드 또는 기계 코드)으로 출력합니다. 따라서 테스트 사례를 쉽게 만들고 확인할 수 있습니다.
또한, 버그는 재현하기도 쉽습니다. 정확한 플랫폼 및 컴파일러 버전 정보와는 별도로 입력 코드 만 있으면됩니다. 컴파일러 사용자 (개발자 자신)는 일반적인 컴퓨터 사용자보다 훨씬 더 정확하고 자세한 버그 보고서를 제공하는 경향이 있습니다 :-)
지금까지의 모든 위대한 답변 외에도
"관찰자 편견"이 있습니다. 버그는 관찰되지 않으므로 버그가 없다고 가정합니다.
당신처럼 생각 했었어 그런 다음 전문적으로 컴파일러를 작성하기 시작했으며 거기에 많은 버그가 있습니다.
사람들이 작성하는 나머지 모든 코드의 99.999 %와 유사한 코드를 작성하기 때문에 버그가 표시되지 않습니다. 메서드를 호출하고 루프를 실행하고 정상적인 비즈니스 문제를 해결하는 일반 개발자이기 때문에 환상적이고 이상한 작업을 수행하지 않는 완전히 정상적이고 간단하며 명확하게 올바른 코드를 작성할 수 있습니다.
컴파일러 버그는 분석하기 쉬운 일반 코드 시나리오가 아니기 때문에 컴파일러 버그가 표시되지 않습니다. 버그는 작성하지 않은 이상한 코드 분석에 있습니다.
반면에 나는 반대 관찰자 편견이 있습니다. 매일 매일 미친 코드가 보이므로 컴파일러는 버그로 가득 찬 것 같습니다.
모든 언어의 언어 사양에 동의하고 해당 언어에 대한 컴파일러 구현을 사용하여 모호한 경우에 집중하여 컴파일러가 정확하게 사양을 구현했는지 여부를 결정하려고 열심히 노력했다면 곧 발견 될 것입니다. 컴파일러 버그가 자주 발생합니다. 예를 들어 보겠습니다. 문자 그대로 5 분 전에 찾은 C # 컴파일러 버그가 있습니다.
static void N(ref int x){}
...
N(ref 123);
컴파일러는 세 가지 오류를 제공합니다.
분명히 첫 번째 오류 메시지는 정확하고 세 번째 오류 메시지는 버그입니다. 오류 생성 알고리즘은 첫 번째 인수가 왜 유효하지 않은지 알아 내려고합니다.이를보고, 상수인지, 소스 코드로 돌아가서 "ref"로 표시되어 있는지 확인하지 않습니다. 오히려 상수를 참조로 표시하기에 어리석은 사람은 없다고 가정하고 참조가 누락되어야한다고 결정합니다.
올바른 세 번째 오류 메시지가 무엇인지는 확실하지 않지만 그렇지 않습니다. 실제로 두 번째 오류 메시지가 올바른지 확실하지 않습니다 . 과부하 해결에 실패하거나 "ref 123"을 올바른 유형의 ref 인수로 취급해야합니까? 이제 올바른 행동이 무엇인지 판단 할 수 있도록 몇 가지 생각을하고 심사 팀과상의해야합니다.
123을 ref로 전달하려고 시도하는 것처럼 어리석은 짓을하지 않기 때문에이 버그를 본 적이 없습니다. 그리고 만약 그렇다면, 첫 번째 오류 메시지가 정확하고 문제를 진단하기에 충분하기 때문에 세 번째 오류 메시지가 의미가 없다는 것을 알지 못할 것입니다. 그러나 컴파일러를 깨 려고 하기 때문에 그런 일을 하려고 합니다. 당신이 시도하면 버그도 볼 수 있습니다.
농담 해? 컴파일러에도 버그가 있으며 실제로로드됩니다.
GCC는 아마도 지구상에서 가장 유명한 오픈 소스 컴파일러이며 버그 데이터베이스를 살펴보십시오. http://gcc.gnu.org/bugzilla/buglist.cgi?product=gcc&component=c%2B%2B&resolution=-- -
GCC 3.2와 GCC 3.2.3 사이에서 수정 된 버그 수를 살펴보십시오. http://gcc.gnu.org/gcc-3.2/changes.html
Visual C ++와 같은 다른 사람들은 시작조차 원하지 않습니다.
컴파일러를 어떻게 안정적으로 만들 수 있습니까? 처음에는 부하와 단위 테스트가 있습니다. 그리고 지구 전체가 테스터를 어지럽히 지 않도록 사용합니다.
진지하게, 내가 믿는 컴파일러 개발자는 뛰어난 프로그래머이며, 완벽하지는 않지만, 상당히 펀치감이 듭니다.
나는 하루에 두세 번 만났다. 하나를 감지하는 유일한 방법은 어셈블리 코드를 보는 것입니다.
다른 포스터가 지적한 이유로 컴파일러는 신뢰성이 높지만 컴파일러 신뢰성은 종종 자체 이행 평가라고 생각합니다. 프로그래머는 컴파일러를 표준으로 간주하는 경향이 있습니다. 문제가 발생하면 결함이 있다고 가정하고 (현재 시간의 99.999 % 때문) 코드를 변경하여 컴파일러 문제를 해결하십시오. 예를 들어, 높은 최적화 설정에서 충돌하는 코드는 분명히 컴파일러 버그이지만 대부분의 사람들은 버그를 조금만 설정하고 버그를보고하지 않고 계속 진행합니다.
컴파일러에는 정확성으로 이어지는 몇 가지 속성이 있습니다.
우리는 매일 컴파일러를 사용합니다
... 그리고 컴파일러를 어떻게 그렇게 안정적으로 만들 수 있습니까?
그들은하지 않습니다. 우리는하다. 모두가 항상 그것들을 사용 하기 때문에 버그가 빨리 발견됩니다.
숫자 게임입니다. 컴파일러는 광범위하게 사용되기 때문에 누군가 버그 가 발생할 가능성이 높지만 사용자가 너무 많기 때문에 누군가가 당신을 구체적으로 대변 할 가능성 은 거의 없습니다 .
따라서 사용자의 관점에 따라 다릅니다. 모든 사용자에게 컴파일러는 버그가 있습니다. 그러나 당신이 한 전에 경우에, 그래서 다른 사람의 코드와 비슷한 조각을 컴파일 할 가능성이 높다 이었다 버그, 그것은 당신을을하지 포함했는지 것이다 당신의에서, 그래서 각각의 버그처럼 보이는, 관점 절대 거기.
물론 그 외에도 여기에 다른 모든 대답을 추가 할 수 있습니다. 컴파일러는 잘 연구되고 잘 이해되어 있습니다. 쓰기가 어렵다는 신화가 있습니다. 이는 매우 똑똑하고 훌륭한 프로그래머 만이 실제로 작성하려고 시도 할 때주의를 기울입니다. 일반적으로 테스트하기 쉽고 스트레스 테스트 또는 퍼지 테스트가 쉽습니다. 컴파일러 사용자는 전문 프로그래머 인 경향이 있으므로 고품질 버그 보고서가 생성됩니다. 그리고 다른 방법 : 컴파일러 작성자는 자신의 컴파일러 사용자 인 경향이 있습니다.
나는 종종 컴파일러 버그에 부딪쳤다.
테스터가 적은 어두운 구석에서 찾을 수 있습니다. 예를 들어 GCC에서 버그를 찾으려면 다음을 시도하십시오.
일반적으로 -O0에 매우 적합합니다. 실제로 컴파일러 버그가 의심되면 -O0과 사용하려는 수준을 비교합니다. 최적화 수준이 높을수록 위험이 커집니다. 일부는 일부러 의도적으로 문서화되어 있습니다. 나는 (많은 시간 동안 적어도 백) 많은 사람들을 만났지만 최근에는 훨씬 더 희귀 해지고 있습니다. 그럼에도 불구하고, 좋은 스펙 마크 수 (또는 마케팅에 중요한 다른 벤치 마크)를 추구함에있어 한계를 뛰어 넘는 유혹은 크다. 우리는 이름이없는 벤더가 명확하게 레이블이 지정된 컴파일 옵션 대신 괄호를 기본값으로 설정하기로 결정한 몇 년 전에 문제가있었습니다.
컴파일러 오류를 진단하고 스트레이 메모리 참조를 말하기가 어려울 수 있습니다. 다른 옵션을 사용하여 다시 컴파일하면 메모리 내에서 데이터 객체의 상대적 위치가 단순히 뒤섞 일 수 있으므로 소스 코드의 Heisenbug인지 버그인지 알 수 없습니다. 컴파일러. 또한 많은 최적화는 연산 순서에 따라 합법적으로 변경하거나 대수를 대수적으로 단순화하며 부동 소수점 반올림 및 언더 / 오버플로와 관련하여 다른 속성을 갖습니다. 이러한 효과를 REAL 버그와 분리하기는 어렵습니다. 이러한 이유로 하드 코어 부동 소수점 컴퓨팅은 어렵습니다. 버그와 수치 적 감도는 종종 풀기 어렵 기 때문입니다.
컴파일러 버그는 그리 드물지 않습니다. 가장 일반적인 경우는 컴파일러가 수락해야하는 코드에 대한 오류를보고하거나 컴파일러가 거부 된 코드를 수락하는 경우입니다.
그렇습니다. 어제 ASP.NET 컴파일러에서 버그가 발생했습니다.
뷰에서 강력한 형식의 모델을 사용하는 경우 템플릿에 포함 할 수있는 매개 변수 수에 제한이 있습니다. 분명히 4 개의 템플릿 매개 변수를 사용할 수 없으므로 아래 두 예제 모두 컴파일러가 처리하기에는 너무 많은 양을 만듭니다.
ViewUserControl<System.Tuple<type1, type2, type3, type4, type5>>
그대로 컴파일하지 않지만 type5
제거 하면 됩니다.
ViewUserControl<System.Tuple<MyModel, System.Func<type1, type2, type3, type4>>>
type4
제거 하면 컴파일 됩니다.
참고 System.Tuple
많은 과부하를 가지고 있으며, 16 매개 변수 (이 미친 내가 아는)까지 걸릴 수 있습니다.
컴파일러 자체에 버그가 발생한 적이 있습니까? 이것이 무엇이며 컴파일러 자체에 문제가 있다는 것을 어떻게 알았습니까?
예!
가장 기억에 남는 두 가지는 내가 처음 만난 두 사람입니다. 둘 다 약 1985-7 년에 680x0 Mac 용 Lightspeed C 컴파일러에있었습니다.
첫 번째는 어떤 상황에서는 정수 후행 증가 연산자가 아무 것도하지 않은 곳입니다. 즉, 특정 코드에서 "i ++"는 단순히 "i"에 대해 아무 것도하지 않았습니다. 나는 분해를 볼 때까지 머리를 뽑고 있었다. 그런 다음 방금 증가를 다른 방식으로 수행하고 버그 보고서를 제출했습니다.
두 번째는 조금 더 복잡했고 실제로 잘못 고려 된 "기능"이었습니다. 초기 맥은 저수준 디스크 작업을 수행하기위한 복잡한 시스템을 가지고있었습니다. 어떤 이유로 든 컴파일러가 객체 코드에서 디스크 작업 명령을 대신 생성하는 대신, 실행 파일을 작게 만드는 것과 관련이 없었습니다 .Lightspeed 컴파일러는 내부 함수를 호출하여 런타임에 디스크 작업을 생성했습니다. 스택에 대한 지시 사항으로 이동했습니다.
그것은 68000 CPU에서 훌륭하게 작동했지만 68020 CPU에서 동일한 코드를 실행하면 종종 이상한 일을합니다. 68020의 새로운 기능은 기본 명령 256 바이트 명령 캐시라는 것이 밝혀졌습니다. 초기에는 CPU 캐시가 있었지만 캐시가 "더러워"리필이 필요하다는 개념은 없었습니다. 모토로라의 CPU 디자이너들은 자체 수정 코드에 대해 생각하지 않았다고 생각합니다. 따라서 실행 순서에서 두 개의 디스크 작업을 충분히 가깝게 수행하고 Lightspeed 런타임이 스택의 동일한 위치에 실제 명령을 빌드 한 경우 CPU는 명령 캐시가 충돌했다고 생각하여 첫 번째 디스크 작업을 두 번 실행합니다.
다시 한 번, 디스어셈블러를 사용하여 파고 들었고, 저수준 디버거에서 많은 단일 스테핑을 수행했습니다. 내 해결 방법은 모든 디스크 작업 앞에 256 개의 "NOP"명령을 수행 한 함수를 호출하여 명령 캐시를 플러딩 (및 삭제)하는 것이 었습니다.
그 이후로 25 년 동안, 시간이 지남에 따라 점점 더 많은 컴파일러 버그가 발견되었습니다. 나는 몇 가지 이유가 있다고 생각합니다.
5.5 년 전에 Turbo Pascal에서 눈부신 오류가 발견되었습니다. 컴파일러의 이전 (5.0) 또는 다음 (6.0) 버전에 오류가 없습니다. 그리고 모퉁이가 아니기 때문에 (테스트가 쉽지 않은 테스트) (일반적으로 사용되지 않는 호출).
일반적으로, 취미 프로젝트가 아닌 상용 컴파일러 빌더는 매우 광범위한 QA 및 테스트 절차를 갖추고 있습니다. 그들은 그들의 컴파일러가 그들의 주력 프로젝트라는 것을 알고 있으며, 대부분의 다른 제품을 만드는 다른 회사를 보는 것보다 결함이 매우 나빠 보일 것입니다. 소프트웨어 개발자는 용서할 수없는 도구입니다. 툴 공급 업체를 통해 공급 업체의 수정을 기다리지 않고 대안을 찾을 수있을 것입니다. 예. 그렇지 않은 많은 다른 산업에서는 심각한 버그로 인해 컴파일러 제작자에 대한 잠재적 손실이 비디오 편집 소프트웨어 제작자보다 훨씬 큽니다.
-O0 및 -O2로 컴파일 할 때 소프트웨어의 동작이 다르면 컴파일러 버그를 발견 한 것입니다.
소프트웨어의 동작이 예상과 다른 경우 버그가 코드에있을 가능성이 있습니다.
컴파일러 버그가 발생하지만 이상한 구석에있는 경향이 있습니다 ...
1990 년대에 Digital Equipment Corporation VAX VMS C 컴파일러에 이상한 버그가있었습니다.
(저는 당시 유행과 마찬가지로 벨트에 양파를 입고있었습니다)
for 루프 앞에있는 외부 세미콜론은 for 루프의 본문으로 컴파일됩니다.
f(){...}
;
g(){...}
void test(){
int i;
for ( i=0; i < 10; i++){
puts("hello");
}
}
해당 컴파일러에서 루프는 한 번만 실행됩니다.
그것은 본다
f(){...}
g(){...}
void test(){
int i;
for ( i=0; i < 10; i++) ; /* empty statement for fun */
{
puts("hello");
}
}
시간이 많이 걸렸습니다.
우리가 업무 경험에 영향을 미쳤던 PIC C 컴파일러의 이전 버전은 학생들이 우선 순위가 높은 인터럽트를 올바르게 사용한 코드를 생성 할 수 없었습니다. 2-3 년을 기다려 업그레이드해야했습니다.
MSVC 6 컴파일러는 링커에 멋진 버그가 있었으며 오류를 세분화하고 이유없이 죽습니다. 깨끗한 빌드는 일반적으로 그것을 고쳤습니다 (그러나 항상 한숨을 쉬지는 않습니다).
나는 몇 가지 컴파일러 버그를 보았고, 몇 가지를보고했다 (특히 F #에서).
즉, 컴파일러를 작성하는 사람들은 일반적으로 컴퓨터 과학의 엄격한 개념에 매우 익숙하여 코드의 수학적 의미에 대해 실제로 의식하게되므로 컴파일러 버그는 드물다고 생각합니다.
그들 대부분은 아마도 람다 미적분학, 공식 검증, denotational semantics 등과 같은 것들에 매우 익숙 할 것입니다. 나 같은 평범한 프로그래머는 거의 이해할 수없는 것들입니다.
또한 일반적으로 컴파일러에서 입력에서 출력으로 상당히 간단한 매핑이 있으므로 프로그래밍 언어를 디버깅하는 것이 블로그 엔진을 디버깅하는 것보다 훨씬 쉽습니다.
얼마 전에 C # 컴파일러에서 버그를 발견했습니다 .C # 디자인 팀의 Eric Lippert가 버그가 무엇인지 어떻게 알았는지 알 수 있습니다 .
이미 주어진 답변 외에도 몇 가지 더 추가하고 싶습니다. 컴파일러 디자이너는 종종 매우 훌륭한 프로그래머입니다. 컴파일러는 매우 중요합니다. 대부분의 프로그래밍은 컴파일러를 사용하여 수행되므로 컴파일러의 품질이 중요합니다. 따라서 최고의 사람들을 배치하기 위해 컴파일러를 만드는 회사 (또는 적어도 좋은 사람들 : 컴파일러 디자인을 좋아하지 않을 수도 있음)는 회사의 이익에 가장 큰 관심을 기울입니다. Microsoft는 C 및 C ++ 컴파일러가 제대로 작동하기를 원하거나 회사의 나머지 작업을 수행 할 수 없습니다.
또한 복잡한 컴파일러를 작성하는 경우 함께 해킹 할 수 없습니다. 컴파일러의 논리는 매우 복잡하고 공식화하기 쉽습니다. 따라서 이러한 프로그램은 종종 매우 견고하고 일반적인 방식으로 작성되므로 버그가 줄어 듭니다.