2013-03-07 6 views
9

क्लैंग के साथ एक बड़ी परियोजना को संकलित करते समय मैंने एक परेशान बग पर ठोकर खाई।एलएलवीएम अनुकूलन बग या अपरिभाषित व्यवहार?

निम्नलिखित छोटा सा उदाहरण पर विचार करें:

unsigned long int * * fee(); 

void foo(unsigned long int q) 
{ 
    unsigned long int i,j,k,e; 
    unsigned long int pows[7]; 
    unsigned long int * * table; 

    e = 0; 
    for (i = 1; i <= 256; i *= q) 
    pows[e++] = i; 
    pows[e--] = i; 

    table = fee(); // need to set table to something unknown 
        // here, otherwise the compiler optimises 
        // parts of the loops below away 
        // (and no bug occurs) 

    for (i = 0; i < q; i++) 
    for (j = 0; j < e; j++) 
     ((unsigned char*)(*table) + 5)[i*e + j] = 0; // bug here 
} 
मेरी जानकारी के अनुसार करने के लिए

इस कोड, (, कोड इस तरह किसी भी तरह से सी मानक का उल्लंघन नहीं करता है, हालांकि अंतिम पंक्ति अजीब लगता है वास्तविक परियोजना में प्रीप्रोसेसर मैक्रोज़ के अत्यधिक उपयोग के कारण प्रकट होता है)।

ऑप्टिमाइज़ेशन स्तर पर क्लैंग (संस्करण 3.1 या उच्चतम) के साथ इसे संकलित करना - ओ 1 या उच्चतर परिणाम स्मृति में गलत स्थिति में कोड लेखन में परिणाम। इस प्रकार

विधानसभा बजना द्वारा उत्पादित फ़ाइल के महत्वपूर्ण भागों/LLVM पढ़ें: (यह, गैस वाक्य रचना है, इसलिए जो इंटेल के लिए किया जाता आप में से उन लोगों के लिए: सावधान!)

[...] 
    callq _fee 
    leaq 6(%rbx), %r8   ## at this point, %rbx == e-1 
    xorl %edx, %edx 
LBB0_4: 
    [...] 
    movq %r8, %rsi 
    imulq %rdx, %rsi 
    incq %rdx 
LBB0_6: 
    movq (%rax), %rcx   ## %rax == fee() 
    movb $0, (%rcx,%rsi) 
    incq %rsi 
    [conditional jumps back to LBB0_6 resp. LBB0_4] 
    [...] 

अन्य में शब्द, निर्देश

(*table)[i*(e+5) + j] = 0; 

ऊपर लिखी गई अंतिम पंक्ति के बजाय निर्देश करते हैं। + 5 की पसंद मनमाने ढंग से है, अन्य अभिकर्मकों को जोड़ने (या घटाना) एक ही व्यवहार में परिणाम। तो - क्या यह एलएलवीएम के अनुकूलन में एक बग है या यहां पर अनिश्चित व्यवहार चल रहा है?

संपादित करें: ध्यान दें कि अगर मैं अंतिम पंक्ति में (unsigned char*) कास्ट छोड़ देता हूं तो बग गायब हो जाता है। आम तौर पर, बग किसी भी बदलाव के लिए काफी संवेदनशील प्रतीत होता है।

+1

उपरोक्त असेंबलर कोड में 5 से गुणा को नहीं देख सकता (लेकिन फिर इंटेल की तुलना में एआरएम असेंबलर के लिए अधिक उपयोग किया जाता है, अगर यह इंटेल है :-)), लेकिन, सी कोड की अंतिम पंक्ति '* ((हस्ताक्षरित चार *) (* तालिका) + 5 + i * ई + जे) ', तो ... क्या आप वाकई असेंबलर आउटपुट की अपनी व्याख्या में "ई + 5" के आसपास उन ब्रेसिज़ को सही ढंग से रखते हैं? – user2116939

+0

हां, मुझे पूरा यकीन है। यह जीएएस सिंटैक्स है, इंटेल नहीं, इसलिए 'movq% r8,% rsi' और 'imulq% rdx,% rsi' का अर्थ है कि'% rsi' '(% rbx + 6) *% rdx = (e + 5) *% rdx'। –

+0

हां, अब मैं इसे देख सकता हूं। यह एक ऑप्टिमाइज़र बग की तरह दिखता है क्योंकि कोड थोड़ी अजीब है (लेकिन फिर मैक्रोज़ अजीब आउटपुट उत्पन्न कर सकते हैं) कोड कोशर पर्याप्त है। – user2116939

उत्तर

5

मुझे पूरा यकीन है कि यह एक अनुकूलक बग है। यह एलएलवीएम-2.7 और एलएलवीएम-3.1 में रेपो है, मेरे पास केवल एक ही संस्करण है।

मैंने एलएलवीएम बगजिला में a bug पोस्ट किया।

बग इस SSCCE द्वारा दर्शाया गया है:

#include <stdio.h> 

unsigned long int * table; 

void foo(unsigned long int q) 
{ 
    unsigned long int i,j,e; 

    e = 0; 
    for (i = 1; i <= 256; i *= q) 
    e++; 
    e--; 

    for (i = 0; i < q; i++) 
    for (j = 0; j < e; j++) 
     ((unsigned char*)(table) + 13)[i*e + j] = 0; // bug here 
} 

int main() { 
    unsigned long int v[8]; 
    int i; 
    memset(v, 1, sizeof(v)); 

    table = v; 
    foo(2); 

    for(i=0; i<sizeof(v); i++) { 
     printf("%d", ((unsigned char*)v)[i]); 
    } 
    puts(""); 
    return 0; 
} 

यह

1111111111111000000000000000011111111111111111111111111111111111 
जीसीसी और "बजना -O0" के अंतर्गत

प्रिंट चाहिए। एलएलवीएम के साथ देखा गया गलत आउटपुट

0000000011111111111110000000011111111111111111111111111111111111 

यह ध्यान देने के लिए धन्यवाद!

संबंधित मुद्दे