ในโหมดเผยแพร่ลักษณะการทำงานของโค้ดไม่เป็นไปตามที่คาดไว้


131

รหัสต่อไปนี้สร้างผลลัพธ์ที่แตกต่างกันภายใต้โหมดดีบักและโหมดเผยแพร่ (โดยใช้ Visual Studio 2008):

int _tmain(int argc, _TCHAR* argv[])
{

    for( int i = 0; i < 17; i++ ) 
    { 
        int result = i * 16;

        if( result > 255 )
        {
            result = 255;
        }

        printf("i:%2d, result = %3d\n", i, result) ; 
    } 

    return 0;
}

ผลลัพธ์ของโหมดดีบักซึ่งเป็นไปตามที่คาดไว้:

i: 0, result =   0
i: 1, result =  16
(...)
i:14, result = 224
i:15, result = 240
i:16, result = 255

เอาต์พุตของโหมดรีลีสโดยที่ผลลัพธ์ i: 15 ไม่ถูกต้อง:

i: 0, result =   0
i: 1, result =  16
(...)
i:14, result = 224
i:15, result = 255
i:16, result = 255

เมื่อเลือก "การเพิ่มประสิทธิภาพ -> ไม่ให้เหมาะสม" ใน Visual Studio ภายใต้โหมดเผยแพร่ผลลัพธ์ที่ได้จะถูกต้อง อย่างไรก็ตามฉันต้องการทราบว่าเหตุใดกระบวนการเพิ่มประสิทธิภาพจึงอาจนำไปสู่ผลลัพธ์ที่ผิดพลาดได้


ปรับปรุง:

ตามคำแนะนำของ Mohit JainBy พิมพ์โดย:

printf("i:%2d, result = %3d, i*16=%d\n", i, result, i*16) ;

เอาต์พุตโหมดปลดถูกต้อง:

i: 0, result =   0, i*16=0
i: 1, result =  16, i*16=16
(...)
i:14, result = 224, i*16=224
i:15, result = 240, i*16=240
i:16, result = 255, i*16=256

15
ดูเหมือนว่าเป็นบั๊กของคอมไพเลอร์ (และเป็นข้อผิดพลาดที่ค่อนข้างสำคัญ)
WhozCraig

1
@WhozCraig เพียงแค่อัปเดตผลลัพธ์ของi * 16ในโพสต์และผลลัพธ์ก็ถูกต้อง
Lorris Lin

4
@juanchopanza: จากประสบการณ์ของฉันกับ MS และการแก้ไขข้อบกพร่องไปจนถึง VS พวกเขาแก้ไขข้อบกพร่องดังกล่าวหลังจากที่ได้รับแจ้งเกี่ยวกับพวกเขา แต่อย่าใช้การแก้ไขเหล่านั้นกับ VS เวอร์ชันเก่าดังนั้นหากมีเหตุผลบางอย่างที่บังคับให้ใช้เวอร์ชันเก่ากว่าของ VS แล้วมีคนหนึ่งติดอยู่กับข้อบกพร่องดังกล่าวจนกว่าจะสามารถอัพเกรดเป็นเวอร์ชันที่ใหม่กว่าได้
Kaiserludi

2
FWIW ทำงานได้ดีกับ Visual Studio 2015 ที่กำลังจะมาถึง
ismail

คำตอบ:


115

สิ่งนี้น่าสนใจอย่างน้อยก็จากมุมมองทางประวัติศาสตร์ ฉันสามารถจำลองปัญหาด้วย VC 2008 (15.00.30729.01) และ VC 2010 (16.00.40219.01) (กำหนดเป้าหมายเป็น 32 บิต x86 หรือ 64 บิต x64) ปัญหาไม่เกิดขึ้นกับคอมไพเลอร์ใด ๆ ที่ฉันได้ลองเริ่มต้นด้วย VC 2012 (17.00.61030)

คำสั่งที่ฉันใช้ในการรวบรวม: cl /Ox vc15-bug.cpp /FAsc

เนื่องจาก VC 2008 (และ 2010) ค่อนข้างเก่าและการแก้ไขได้ดำเนินมาเป็นเวลาหลายปีแล้วฉันไม่คิดว่าคุณจะคาดหวังการดำเนินการใด ๆ จาก Microsoft ยกเว้นใช้คอมไพเลอร์รุ่นใหม่ (แม้ว่าอาจมีคนแนะนำวิธีแก้ปัญหา)

ปัญหาคือการทดสอบเพื่อตรวจสอบว่าควรบังคับให้255ทำตามจำนวนลูปแทนที่จะเป็นผลลัพธ์จริงของi * 16นิพจน์ 255และคอมไพเลอร์เพียงแค่ได้รับผิดนับเมื่อมันควรจะเริ่มบังคับให้ค่า ฉันไม่รู้ว่าทำไมมันถึงเกิดขึ้น - มันเป็นเพียงผลกระทบที่ฉันเห็น:

; 6    :    for( int i = 0; i < 17; i++ ) 

  00001 33 f6        xor     esi, esi
$LL4@main:
  00003 8b c6        mov     eax, esi
  00005 c1 e0 04     shl     eax, 4

; 7    :    { 
; 8    :        int result = i * 16;
; 9    : 
; 10   :        if( result > 255 )

  // the value `esi` is compared with in the following line should be 15!
  00008 83 fe 0e     cmp     esi, 14            ; 0000000eH
  0000b 7e 05        jle     SHORT $LN1@main

; 11   :        {
; 12   :            result = 255;

  0000d b8 ff 00 00 00   mov     eax, 255       ; 000000ffH
$LN1@main:

; 13   :        }

อัปเดต : VC ทุกเวอร์ชันที่ฉันติดตั้งไว้ก่อนหน้า VC 2008 มีจุดบกพร่องเหมือนกันยกเว้น VC6 - การคอมไพล์โปรแกรมขัดข้องคอมไพเลอร์ VC6:

vc15-bug.cpp(10) : fatal error C1001: INTERNAL COMPILER ERROR

นี่คือข้อบกพร่องที่เกิดขึ้นใน MSVC ในรูปแบบใดรูปแบบหนึ่งมานานกว่า 10 ปี!


ถ้าหน่วยความจำของฉันเกี่ยวกับเวลาการประกอบ x86 ถูกต้องเหตุผลในการเปรียบเทียบกับ esi แทนที่จะเป็น eax คือ comp eax 255 จะทำให้เกิดการหยุดไปป์ไลน์เนื่องจาก eax เพิ่งถูกเขียน
Loren Pechtel

3
การเดาของฉัน (การแปลง): ผลลัพธ์> 255, ผลลัพธ์ / 16> 255/16, ฉัน> 15, ฉัน <= 14
teki

น่าสนใจมาก! นอกจากนี้ถ้าคุณเปลี่ยนการเปรียบเทียบจากresult > 255ไปresult >= 255มันจะทำงานได้อย่างถูกต้อง ใน VS2010 ว่าการเปลี่ยนแปลงcmp esi, 14ไปcmp esi, 16(และjleจะjl)
opello

16

สมมติว่าข้อเท็จจริงที่คุณรายงานถูกต้องนี่อาจเป็นบั๊กของคอมไพเลอร์ ตรวจสอบเวอร์ชันล่าสุดของคอมไพเลอร์ หากยังคงพบข้อบกพร่องอยู่ให้ส่งรายงานข้อบกพร่อง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.