क्लैंग के साथ एक बड़ी परियोजना को संकलित करते समय मैंने एक परेशान बग पर ठोकर खाई।एलएलवीएम अनुकूलन बग या अपरिभाषित व्यवहार?
निम्नलिखित छोटा सा उदाहरण पर विचार करें:
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*)
कास्ट छोड़ देता हूं तो बग गायब हो जाता है। आम तौर पर, बग किसी भी बदलाव के लिए काफी संवेदनशील प्रतीत होता है।
उपरोक्त असेंबलर कोड में 5 से गुणा को नहीं देख सकता (लेकिन फिर इंटेल की तुलना में एआरएम असेंबलर के लिए अधिक उपयोग किया जाता है, अगर यह इंटेल है :-)), लेकिन, सी कोड की अंतिम पंक्ति '* ((हस्ताक्षरित चार *) (* तालिका) + 5 + i * ई + जे) ', तो ... क्या आप वाकई असेंबलर आउटपुट की अपनी व्याख्या में "ई + 5" के आसपास उन ब्रेसिज़ को सही ढंग से रखते हैं? – user2116939
हां, मुझे पूरा यकीन है। यह जीएएस सिंटैक्स है, इंटेल नहीं, इसलिए 'movq% r8,% rsi' और 'imulq% rdx,% rsi' का अर्थ है कि'% rsi' '(% rbx + 6) *% rdx = (e + 5) *% rdx'। –
हां, अब मैं इसे देख सकता हूं। यह एक ऑप्टिमाइज़र बग की तरह दिखता है क्योंकि कोड थोड़ी अजीब है (लेकिन फिर मैक्रोज़ अजीब आउटपुट उत्पन्न कर सकते हैं) कोड कोशर पर्याप्त है। – user2116939