मुझे कैसे पता चलेगा कि संकलक ने मेरा कोड तोड़ा है और यदि यह संकलक था तो मैं क्या करूं?


14

एक बार थोड़ी देर में C ++ कोड काम नहीं करेगा जब कुछ स्तर के अनुकूलन के साथ संकलित किया जाएगा। यह कंपाइलर ऑप्टिमाइज़ेशन कर सकता है जो कोड को तोड़ता है या यह अपरिभाषित व्यवहार वाला कोड हो सकता है जो कंपाइलर को जो कुछ भी महसूस होता है उसे करने की अनुमति देता है।

मान लीजिए मेरे पास कुछ कोड हैं जो केवल उच्च अनुकूलन स्तर के साथ संकलित होने पर टूट जाते हैं। मुझे कैसे पता चलेगा कि यह कोड या कंपाइलर है और यदि यह कंपाइलर है तो मैं क्या करूं?


43
सबसे अधिक संभावना है कि आप।
littleadv

9
@littleadv, यहां तक ​​कि gcc और msvc के हाल के संस्करण भी बग से भरे हुए हैं, इसलिए मुझे यकीन नहीं होगा।
एसके-लॉजिक

3
आपने सभी चेतावनियाँ सक्षम कर दी हैं?

@ थोरबजर्न रावन एंडरसन: हां, मेरे पास उन्हें सक्षम है।
शार्प फुट

3
एफडब्ल्यूआईडब्ल्यू: 1) मैं कुछ भी मुश्किल नहीं करने की कोशिश करता हूं जो कंपाइलर को गड़बड़ करने के लिए लुभा सकता है, 2) ऑप्टिमाइज़ फ़्लैग मैटर (गति के लिए) एकमात्र स्थान कोड में है जहां प्रोग्राम काउंटर अपने समय का एक महत्वपूर्ण अंश खर्च करता है। जब तक आप तंग सीपीयू लूप नहीं लिख रहे हैं, कई अनुप्रयोगों में पीसी अनिवार्य रूप से अपने सभी समय पुस्तकालयों में, या आई / ओ में गहरा खर्च करता है। इस तरह के ऐप में / O स्विच आपकी मदद नहीं करते हैं।
माइक डनलवे

जवाबों:


19

मैं कहूंगा कि यह एक सुरक्षित शर्त है कि अधिकांश मामलों में, यह आपका कोड है, न कि संकलक, जो टूट गया है। और असाधारण मामले में भी जब यह संकलक है, तो आप शायद कुछ अस्पष्ट भाषा सुविधा का उपयोग असामान्य तरीके से कर रहे हैं, जिसके लिए विशिष्ट संकलक तैयार नहीं है; दूसरे शब्दों में, आप संभवतः अपने कोड को अधिक मुहावरेदार होने के लिए बदल सकते हैं और संकलक के कमजोर स्थान से बच सकते हैं।

किसी भी दर पर, यदि आप यह साबित कर सकते हैं कि आपको एक कंपाइलर बग (भाषा की कल्पना के आधार पर) मिला है, तो इसे कंपाइलर डेवलपर्स को रिपोर्ट करें, ताकि वे इसे कुछ समय के लिए निर्धारित कर सकें।


@ एसके-तर्क, पर्याप्त रूप से, मेरे पास इसे वापस करने के लिए कोई आंकड़े नहीं हैं। यह मेरे अपने अनुभव पर आधारित है, और मैं मानता हूं कि मैंने शायद ही कभी भाषा और / या संकलक की सीमा को बढ़ाया हो - अन्य लोग इसे अधिक बार कर सकते हैं।
पेटर टॉर्क

(1) @ एसके-लॉजिक: बस एक सी ++ कंपाइलर बग पाया गया, एक ही कोड, एक कंपाइलर और कार्यों पर कोशिश की गई, दूसरे में यह कोशिश की गई।
umlcat

8
@umlcat: सबसे अधिक संभावना है कि यह अनिर्दिष्ट व्यवहार के आधार पर आपका कोड था; एक संकलक पर यह आपकी उम्मीदों से मेल खाता है, दूसरे पर यह नहीं है। इसका मतलब यह नहीं है कि यह टूट गया है।
जेवियर

@ रिच मेल्टन, क्या आपने कभी LTO का उपयोग किया है?
तर्क

1
जब मैं गेम कंसोल के बारे में बात कर रहा हूं, तो मैं क्रैशवर्क से सहमत हूं। यह विशिष्ट स्थिति में गूढ़ संकलक कीड़े खोजने के लिए बिल्कुल भी असामान्य नहीं है। यदि आप सामान्य पीसी को लक्षित कर रहे हैं, हालांकि, एक भारी-भरकम संकलक का उपयोग कर रहे हैं, तो यह बहुत संभावना नहीं है कि आप एक कंपाइलर बग में टकराएंगे जो पहले किसी ने नहीं देखा है।
ट्रेवर पॉवेल

14

हमेशा की तरह, किसी भी अन्य कीड़े के साथ: एक नियंत्रित प्रयोग करें। संदिग्ध क्षेत्र को नीचे गिराएं, बाकी सब के लिए अनुकूलन बंद करें और कोड के उस हिस्से पर लागू किए गए अनुकूलन को अलग करना शुरू करें। एक बार जब आप एक 100% प्रतिलिपि प्रस्तुत करने योग्य हो जाते हैं, तो अपने कोड को अलग करना शुरू करें, उन चीजों को पेश करना जो कुछ अनुकूलन को तोड़ सकते हैं (उदाहरण के लिए, संभावित पॉइंटर अलियासिंग का परिचय दें, संभावित दुष्प्रभावों के साथ बाहरी कॉल डालें)। डीबगर में असेंबली कोड को देखने से भी मदद मिल सकती है।


क्या मदद कर सकता है? यदि यह एक कंपाइलर बग है - तो क्या?
littleadv

2
@littleadv, यदि यह एक कंपाइलर बग है, तो आप इसे ठीक करने की कोशिश कर सकते हैं (या बस इसे ठीक से रिपोर्ट करें, पूर्ण विवरण में), या आप यह जान सकते हैं कि भविष्य में इससे कैसे बचा जाए, यदि आप इसे इस्तेमाल करने के लिए बर्बाद कर रहे हैं थोड़ी देर के लिए अपने संकलक का संस्करण। यदि यह आपके स्वयं के कोड के साथ कुछ है, तो कई C ++ - ish बॉर्डरलाइन मुद्दों में से एक, इस तरह की जांच एक बग को ठीक करने और भविष्य में अपनी तरह से बचने में मदद करती है।
तर्क

इसलिए जैसा कि मैंने अपने जवाब में कहा - रिपोर्टिंग के अलावा, उपचार में कोई बहुत अंतर नहीं है, फिर चाहे कोई भी गलती हो।
littleadv

3
@littleadv, एक समस्या की प्रकृति को समझे बिना आप बार-बार इसका सामना करने की संभावना रखते हैं। और अक्सर एक संकलक को अपने दम पर ठीक करने की संभावना होती है। और, हां, यह दुर्भाग्यपूर्ण नहीं है कि C ++ कंपाइलर में एक बग ढूंढना दुर्भाग्यपूर्ण है।
एसके-लॉजिक

10

असेंबली कोड का परीक्षण करें और देखें कि क्या यह आपके स्रोत के लिए कॉल कर रहा है। याद रखें कि ऑड्स बहुत अधिक हैं कि यह कुछ गैर-स्पष्ट फैशन में वास्तव में आपका कोड है।


1
यह वास्तव में इस प्रश्न का एकमात्र उत्तर है। संकलक नौकरी, इस मामले में, आपको C ++ से असेंबली भाषा में लाने के लिए है। आपको लगता है कि यह संकलक है ... संकलक के काम की जांच करें। यह इतना आसान है।
old_timer

7

प्रोग्रामिंग के 30 से अधिक वर्षों में, वास्तविक कंपाइलर (कोड जनरेशन) बग की संख्या जो मुझे मिली है वह अभी भी केवल ~ 10 है। मेरे स्वयं के (और अन्य लोगों के) बगों की संख्या जो मैंने पाई है और उसी अवधि में तय की है, शायद > 10,000 रु। मेरे "अंगूठे का नियम" तब यह है कि संकलक के कारण किसी भी बग के होने की संभावना <0.001 है।


1
तुम भाग्यशाली हो। मेरा औसत एक महीने में लगभग 1 वास्तव में खराब बग है, और मामूली सीमा रेखा मुद्दे एक तरह से अधिक बार हैं। और आपके द्वारा उपयोग किए जा रहे उच्च अनुकूलन स्तर, उच्चतर संकलक त्रुटि संभावनाएं हैं। यदि आप -O3 और LTO का उपयोग करने का प्रयास कर रहे हैं, तो आप कुछ ही समय में उनमें से एक जोड़े को नहीं पाकर बहुत भाग्यशाली होंगे। और मैं केवल रिलीज़ संस्करणों में कीड़े की गणना करता हूं - एक संकलक डेवलपर के रूप में, मैं अपने काम में उस तरह की समस्याओं का बहुत अधिक सामना कर रहा हूं, लेकिन यह गिनती नहीं करता है। मुझे सिर्फ इतना पता है कि कंपाइलर को स्क्रू करना कितना आसान है।
एसके-लॉजिक

2
25 साल और मैंने भी बहुत देखे हैं। संकलक हर साल खराब हो रहे हैं।
old_timer

5

मैंने एक टिप्पणी लिखना शुरू किया और फिर बहुत लंबा और बहुत हद तक तय किया।

मैं तर्क दूंगा कि यह आपका कोड है जो टूट गया है। उस असंभावित घटना में, जिसे आपने संकलक में बग की खोज की है - आपको इसे कंपाइलर डेवलपर्स को रिपोर्ट करना चाहिए, लेकिन यही वह अंतर है जहां समाप्त होता है।

इसका समाधान यह है कि आपत्तिजनक निर्माण की पहचान करें, और इसे फिर से पचाएँ ताकि यह एक ही तर्क को अलग तरीके से करे। यह इस समस्या को हल करने की सबसे अधिक संभावना है, चाहे बग आपकी तरफ हो या कंपाइलर में।


5
  1. अपने कोड को फिर से पढ़ें। सुनिश्चित करें कि आप ASSERTs, या अन्य डीबग (या अधिक सामान्य, कॉन्फ़िगरेशन) विशिष्ट विवरणों में साइड-इफेक्ट्स वाली चीजें नहीं कर रहे हैं। यह भी याद रखें कि एक डिबग बिल्ड मेमोरी में अलग-अलग तरीके से इनिशियलाइज़ किया जाता है - टेल्टेल पॉइंटर वैल्यू जिन्हें आप यहाँ देख सकते हैं: डीबगिंग - मेमोरी एलोकेशन रिप्रेजेंटेशन । विजुअल स्टूडियो के भीतर से दौड़ते समय आप लगभग हमेशा डिबग हीप (यहां तक ​​कि रिलीज मोड में) का उपयोग करते हैं जब तक कि आप स्पष्ट रूप से एक पर्यावरण चर के साथ निर्दिष्ट नहीं करते हैं कि यह वह नहीं है जो आप चाहते हैं।
  2. अपने निर्माण की जाँच करें। वास्तविक संकलक की तुलना में अन्य स्थानों पर जटिल बिल्ड के साथ समस्याएँ आना आम है - निर्भरता अक्सर अपराधी होती है। मुझे पता है कि "आपने पूरी तरह से पुनर्निर्माण की कोशिश की है" लगभग एक उत्तर को संक्रमित करने के रूप में है "आपने खिड़कियों को फिर से स्थापित करने की कोशिश की है", लेकिन यह अक्सर मदद करता है। कोशिश: ए) रिबूटिंग। बी) अपने सभी मध्यवर्ती और आउटपुट फ़ाइलों को हटाने और निर्माण और पुनर्निर्माण।
  3. किसी भी संभावित स्थानों की जाँच करने के लिए अपने कोड के माध्यम से देखें जहाँ आप अपरिभाषित व्यवहार कर रहे हों। यदि आप थोड़ी देर के लिए C ++ में काम कर रहे हैं, तो आपको पता चल जाएगा कि कुछ स्पॉट हैं जहां आपको लगता है कि "मैं निश्चित रूप से निश्चित नहीं हूं कि मुझे यह मानने की अनुमति है ..." - इसे Google या यहां उस विशेष के बारे में पूछें यह देखने के लिए कि यह अपरिभाषित व्यवहार है या नहीं, कोड का प्रकार।
  4. यदि वह अभी भी ऐसा प्रतीत नहीं होता है, तो समस्या पैदा करने वाली फ़ाइल के लिए प्रीप्रोसेसर आउटपुट जेनरेट करें। एक अप्रत्याशित मैक्रो का विस्तार सभी प्रकार के मज़े का कारण बन सकता है (मुझे उस समय की याद दिलाई जाती है जब एक सहकर्मी ने एच के नाम से मैक्रो का फैसला किया था एक अच्छा विचार होगा ...)। अपने प्रोजेक्ट कॉन्फ़िगरेशन के बीच अप्रत्याशित परिवर्तन के लिए प्रीप्रोसेड आउटपुट की जांच करें।
  5. अंतिम उपाय - अब आप वास्तव में संकलक बग भूमि में हैं - विधानसभा आउटपुट को देखें। यह वास्तव में विधानसभा क्या कर रही है, इस पर एक हैंडल पाने के लिए कुछ खुदाई और लड़ाई हो सकती है, लेकिन यह वास्तव में काफी जानकारीपूर्ण है। आप माइक्रो-ऑप्टिमाइजेशन का मूल्यांकन करने के लिए यहां आपके द्वारा उठाए गए कौशल का उपयोग कर सकते हैं, इसलिए सभी खो नहीं गया है।

+1 के लिए "अपरिभाषित व्यवहार।" मैं उस एक को काट चुका हूं। कुछ कोड लिखे जो int + intओवरफ्लो पर निर्भर थे जैसे कि यह एक हार्डवेयर एडीडी निर्देश के लिए संकलित किया गया हो। जीसीसी के पुराने संस्करण के साथ संकलित होने पर यह ठीक काम करता है, लेकिन नए संकलक के साथ संकलित होने पर नहीं। जाहिरा तौर पर जीसीसी में अच्छे लोगों ने फैसला किया कि चूंकि एक पूर्णांक अतिप्रवाह का परिणाम अपरिभाषित है, इसलिए उनका अनुकूलक इस धारणा के तहत काम कर सकता है कि ऐसा कभी नहीं होता है। यह कोड से बाहर एक महत्वपूर्ण शाखा को अनुकूलित करता है।
सोलोमन स्लो

2

यदि आप जानना चाहते हैं कि यह आपका कोड है या कंपाइलर है, तो आपको C ++ के विनिर्देशन को पूरी तरह से जानना होगा।

यदि संदेह बना रहता है, तो आपको x86 असेंबली को पूरी तरह से जानना होगा।

यदि आप दोनों पूर्णता को सीखने के मूड में नहीं हैं, तो यह लगभग निश्चित रूप से एक अपरिभाषित व्यवहार है जो आपके कंपाइलर अनुकूलन स्तर के आधार पर अलग-अलग हल करता है।


(+1) @mouviciel: यह इस बात पर भी निर्भर करता है कि फीचर इसके कंपाइलर द्वारा समर्थित है, भले ही इसके विनिर्देशन में। मेरे पास जीसीसी के साथ एक अजीब बग है। मैं एक "फ़ंक्शन पॉइंटर" के साथ "सादे सी संरचना" घोषित करता हूं, इसकी विनिर्देश में अनुमति है, लेकिन कुछ स्थितियों में काम करता है, और दूसरे में नहीं।
umlcat

1

मानक कोड या आंतरिक संकलित त्रुटि पर एक संकलन त्रुटि होने से ऑप्टिमाइज़र के गलत होने की संभावना अधिक होती है। लेकिन मैंने कंपाइलर्स के बारे में सुना है कि कुछ साइड इफेक्ट्स को गलत तरीके से भूल जाने से लूप्स का अनुकूलन हो जाता है।

मेरे पास कोई सुझाव नहीं है कि कैसे पता करें कि आप या संकलक। आप एक और संकलक आज़मा सकते हैं।

एक दिन मैं सोच रहा था कि यह मेरा कोड है या नहीं और किसी ने मुझे सुझाव दिया है। मैंने इसके साथ अपना कार्यक्रम चलाने के लिए 5 या 10 मिनट खर्च किए (मुझे लगता है valgrind --leak-check=yes myprog arg1 arg2कि यह किया था, लेकिन मैं अन्य विकल्पों के साथ खेला था) और इसने तुरंत मुझे एक पंक्ति दिखाई जो कि एक विशेष मामले के तहत चलाई जाती है जो कि समस्या थी। तब मेरा ऐप बिना किसी क्रैश क्रैश, त्रुटियों या अजीब व्यवहार के कभी भी सुचारू रूप से चला। valgrind या इसके जैसे कोई अन्य टूल यह जानने का एक अच्छा तरीका है कि क्या आपका कोड है।

साइड नोट: मैंने एक बार सोचा कि मेरे ऐप के प्रदर्शन ने क्यों चूसा। यह मेरी सभी प्रदर्शन समस्याओं के साथ-साथ एक पंक्ति में था। मैंने लिखा है for(int i=0; i<strlen(sz); ++i) {। Sz कुछ mb था। किसी कारणवश कंपाइलर ऑप्टिमाइज़ेशन के बाद भी हर बार स्ट्रगल करता है। एक लाइन बड़ी बात हो सकती है। प्रदर्शन से लेकर क्रैश तक


1

एक तेजी से सामान्य स्थिति यह है कि सी मानक की अनिवार्य व्यवहारों के लिए सी के बोलियों के लिए लिखे गए कोड को कंपाइलर तोड़ता है, मानक के अनुसार अनिवार्य नहीं है, और उन बोलियों को लक्षित करने वाले कोड को सख्ती से अनुरूप कोड की तुलना में अधिक कुशल होने की अनुमति देता है। ऐसे मामले में, "टूटा हुआ" कोड के रूप में वर्णन करना अनुचित होगा, जो संकलक पर 100% विश्वसनीय होगा, जो लक्ष्य बोली को लागू करता है, या "टूटी हुई" संकलक के रूप में वर्णन करने के लिए जो आवश्यक बोली का समर्थन नहीं करने वाली बोली को संसाधित करता है । इसके बजाय, समस्याएं बस इस तथ्य से उपजी हैं कि सक्षम किए गए अनुकूलन के साथ आधुनिक संकलक द्वारा संसाधित की गई भाषा बोलियों से विचलन कर रही है, जो लोकप्रिय हुआ करती थी (और अभी भी कई अनुकूलन द्वारा अक्षम किए गए अनुकूलन के साथ संसाधित होती है, या कुछ के साथ अनुकूलन भी सक्षम होता है)।

उदाहरण के लिए, कई कोड बोलियों के लिए लिखे गए हैं, जो मानक की gcc व्याख्या द्वारा अनिवार्य नहीं होने वाले कई सूचक उपनामों के रूप में पहचानते हैं, और कोड के सीधे अनुवाद को अधिक पठनीय और कुशल बनाने के लिए ऐसे पैटर्न का उपयोग करते हैं। सी मानक की gcc व्याख्या के तहत संभव होगा। ऐसा कोड जीसीसी के साथ संगत नहीं हो सकता है, लेकिन इसका मतलब यह नहीं है कि यह टूट गया है। यह केवल उन एक्सटेंशनों पर निर्भर करता है जो केवल अनुकूलन योग्य अनुकूलन के साथ समर्थन करते हैं।


ठीक है, सुनिश्चित करें कि सी मानक एक्स + एक्सटेंशन वाई और जेड कोडिंग में कुछ भी गलत नहीं है, जब तक कि यह आपको महत्वपूर्ण लाभ देता है, आपको पता है कि आपने ऐसा किया था, और आपने इसे अच्छी तरह से प्रलेखित किया। अफसोस की बात है कि सभी तीन स्थितियां सामान्य रूप से पूरी नहीं हुई हैं , और इस प्रकार यह कहना उचित है कि कोड टूट गया है।
डेडुप्लिकेटर

@Deduplicator: C89 कंपाइलरों को अपने पूर्ववर्तियों के साथ उर्ध्व-अनुकूल होने के रूप में प्रचारित किया गया था, और इसी तरह C99 आदि के लिए, जबकि C89 उन व्यवहारों पर कोई आवश्यकता नहीं लगाता है जो पहले कुछ प्लेटफार्मों पर परिभाषित किए गए थे, लेकिन अन्य नहीं, ऊपर की ओर अनुकूलता का सुझाव होगा कि C89 कंपाइलर जिन प्लेटफार्मों ने व्यवहार को परिभाषित किया था, उन्हें ऐसा करना जारी रखना चाहिए; संकेत के लिए छोटे अहस्ताक्षरित प्रकारों को बढ़ावा देने के लिए तर्क यह बताता है कि मानक के लेखकों ने उम्मीद की थी कि मानक इस तरह से व्यवहार करेंगे कि क्या मानक ने इसे अनिवार्य किया या नहीं। आगे ...
सुपर

... अलियासिंग नियमों की सख्त व्याख्या खिड़की के ऊपर की संगतता को बाहर फेंक देती है और कई प्रकार के कोड को असाध्य बना देती है, लेकिन कुछ मामूली मोड़ (जैसे कुछ पैटर्न की पहचान करना जहां क्रॉस-टाइप अलियासिंग की उम्मीद की जानी चाहिए और इसलिए अनुमेय) दोनों समस्याओं को हल करेगा। । नियम का पूरा उद्देश्य "निराशावादी" उपनामों की धारणा बनाने के लिए संकलक की आवश्यकता से बचने के लिए था, लेकिन "फ्लोट एक्स" को देखते हुए, यह अनुमान लगाना चाहिए कि "फू ((* *) & x)" संशोधित हो सकता है, भले ही "फू" न हो टाइप 'फ्लोट * "या" चार * "के किसी भी पॉइंटर्स को" निराशावादी "और" स्पष्ट "माना जा सकता है?
सुपरकैट

0

समस्याग्रस्त स्थान को अलग करें और भाषा व्यवहार के अनुसार क्या होना चाहिए, इस तरह के व्यवहार की तुलना करें। निश्चित रूप से आसान नहीं है, लेकिन आपको यह जानने के लिए क्या करना है (और सिर्फ मान नहीं )।

मैं शायद उस सावधानीपूर्वक नहीं होगा। बल्कि, मैं संकलक निर्माता के समर्थन मंच / मेलिंग सूची से पूछूंगा। यदि यह संकलक में वास्तव में एक बग है, तो वे इसे ठीक कर सकते हैं। शायद यह मेरा कोड वैसे भी होगा। उदाहरण के लिए, थ्रेडिंग में मेमोरी विजिबिलिटी के बारे में भाषा चश्मा काफी उल्टा हो सकता है, और वे कुछ विशिष्ट हार्डवेयर (!) पर कुछ विशिष्ट अनुकूलन झंडे का उपयोग करते समय ही स्पष्ट हो सकते हैं। कुछ व्यवहार कल्पना से अपरिभाषित हो सकते हैं, इसलिए यह कुछ संकलक / कुछ झंडे के साथ काम कर सकता है, और कुछ अन्य के साथ काम नहीं कर सकता है, आदि।


0

सबसे अधिक संभावना है कि आपके कोड में कुछ अपरिभाषित व्यवहार हैं (जैसा कि अन्य ने समझाया है, आपके कंपाइलर की तुलना में आपके कोड में कीड़े होने की बहुत अधिक संभावना है, भले ही C ++ कंपाइलर इतने जटिल हों कि उनमें बग हों; यहां तक ​​कि C ++ विनिर्देशन में डिज़ाइन बग हैं) । और यूबी यहां भी हो सकता है अगर संकलित निष्पादन योग्य काम करने के लिए होता है (दुर्भाग्य से)।

इसलिए आपको Lattner का ब्लॉग पढ़ना चाहिए। प्रत्येक C प्रोग्रामर को अपरिभाषित व्यवहार के बारे में पता होना चाहिए (अधिकांश यह C ++ 11 के लिए लागू होता है)।

Valgrind उपकरण, और हाल के -fsanitize= उपकरण विकल्प के लिए जीसीसी (या बजना / LLVM ), भी मददगार होना चाहिए। और हां, सभी चेतावनी सक्षम करें:g++ -Wall -Wextra

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.