2010-03-22 10 views
7

के व्यवहार को कैसे परिवर्तित कर सकता है मैं एक बहुत ही दुर्घटनाग्रस्त दुर्घटना को ट्रैक करने की कोशिश कर रहा हूं। इसके बारे में इतना अजीब बात यह है कि कोई कामकाज है जिसे किसी ने खोजा और जिसे मैं समझा नहीं सकता।निष्पादन प्रोग्राम

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

int main(int argc, char *argv[]) 
{ 
    if (argc == 1) 
    { 
     fprintf(stderr, "Usage: %s prog [args ...]\n", argv[0]); 
     return 1; 
    } 

    execvp(argv[1], argv + 1); 

    fprintf(stderr, "execv failed: %s\n", strerror(errno)); 

    // If exec returns because the program is not found or we 
    // don't have the appropriate permission 
    return 255; 
} 

आप देख सकते हैं, सभी को इस कार्यक्रम करता execvp का उपयोग एक अलग कार्यक्रम के साथ ही बदलने के लिए है:

वैकल्पिक हल इस छोटे से प्रोग्राम है जो मैं 'धावक' के रूप में उल्लेख करेंगे।

कार्यक्रम दुर्घटनाओं जब यह सीधे कमांड लाइन से शुरू हो जाती है:

/path/to/prog args # this crashes 

लेकिन ठीक काम करता है जब यह परोक्ष रूप से मेरी धावक शिम के माध्यम से शुरू हो जाती है:

/path/to/runner /path/to/prog args # works successfully 

मुझे के जीवन के लिए, मैं यह समझ सकता हूं कि अतिरिक्त निष्पादन कैसे चल रहा है, इस कार्यक्रम के व्यवहार को बदल सकता है (जैसा कि आप देख सकते हैं कि कार्यक्रम पर्यावरण को नहीं बदलता है)।

दुर्घटना पर कुछ पृष्ठभूमि। क्रैश स्वयं सी ++ रनटाइम में हो रहा है। विशेष रूप से, जब प्रोग्राम throw करता है, तो क्रैशिंग संस्करण गलत तरीके से सोचता है कि कोई मिलान करने वाला कैच नहीं है (हालांकि वहां है) और terminate पर कॉल करें। जब मैं धावक के माध्यम से प्रोग्राम का आह्वान करता हूं, तो अपवाद ठीक से पकड़ा जाता है।

मेरा प्रश्न कोई विचार है कि अतिरिक्त निष्पादन निष्पादित कार्यक्रम के व्यवहार को क्यों बदलता है?

+0

मुझे नहीं पता: लेकिन execvp कार्यशील निर्देशिका को बदलता है? आप क्या तर्क पारित कर रहे हैं? –

+0

@MartinYork - AFAIK, 'execvp' कभी भी कार्यशील निर्देशिका को बदलता नहीं है (जिसके लिए 'chdir' पर कॉल की आवश्यकता होती है और धावक ऐसा नहीं करता है)। विशिष्ट तर्क अप्रासंगिक हैं; वर्णित व्यवहार प्रोग्राम को पारित विशिष्ट तर्कों से स्वतंत्र है। –

+1

यदि आप 'execvp()' के बजाय 'execv()' का उपयोग करते हैं तो यह वही काम करता है? – caf

उत्तर

3

यह संभव है कि धावक द्वारा लोड की गई .so फाइलें चलने वाले को सही तरीके से काम कर रही हैं। प्रत्येक बाइनरी को ldd'ing करने का प्रयास करें और देखें कि कोई पुस्तकालय विभिन्न संस्करण/स्थानों को लोड कर रहा है या नहीं।

+1

समस्या यह है कि क्या 'ld-linux.so.2' मुख्य बाइनरी से पहले या बाद में पता स्थान में एक विशिष्ट साझा ऑब्जेक्ट को मानचित्र करता है (वास्तविक बग कहीं और है लेकिन परिस्थितियों के कारण, बग केवल तब प्रकट होता है जब एसओ मैप किया जाता है एक मुख्य पता तब मुख्य बाइनरी)। –

0

अंधेरे में एक शॉट के रूप में: डबल-exec रैम में पर्यावरण चर के क्रम को बदल सकता है।

पर्यावरण पॉइंटर्स के साथ एक स्मृति संरचना है; कर्नेल प्रतियां जो नई प्रक्रिया के पता स्थान में संरचना करती हैं। रैम में तत्वों का वास्तविक क्रम उस प्रतिलिपि के दौरान बदल सकता है (पर्यावरण चर को अर्थात् क्रमशः आदेश नहीं दिया जाता है, लेकिन रैम में पते में ऑर्डर होता है)। दो exec() के साथ, आदेश दो बार संशोधित किया जा सकता है।

रैम में तारों के क्रम में परिवर्तन की एक बदलाव कुछ हद तक अजीब है, लेकिन अजनबी चीजें हुई हैं।

+0

सुझाव के लिए धन्यवाद लेकिन यह ऐसा प्रतीत नहीं होता है। मैंने कच्चे पर्यावरण ब्लॉक को छोड़ दिया और उनके दोनों में एक ही क्रम है। –

0

मुझे आश्चर्य है कि क्या आप argv [0] में कुछ अलग हो रहे हैं जो खोल है। मैं ऊपर जो लिख रहा हूं उससे स्पष्ट रूप से नहीं देख सकता, लेकिन यह संभव है कि आप प्रोग्राम के वास्तविक तर्क के लिए argv [0] सेट कर रहे हों, जबकि खोल इसे अपने नाम के नाम पर सेट करता है (उदाहरण के लिए पूर्ण या छोटा पथ)

+0

@MarkR - आपके सुझाव के लिए धन्यवाद। मैंने धावक को संशोधित किया ताकि 'argv [0]' पथ शामिल नहीं होगा। दुर्भाग्य से, मैं अभी भी वही व्यवहार देख रहा हूं। –

1

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

+0

अन्यथा सामान्य रूप से बाहर निकलने वाले ब्लॉक पर पहुंचने योग्य, वालग्रिंड उस संस्करण पर किसी भी त्रुटि का पता नहीं लगाता है (या वह संस्करण जो उस मामले के लिए समाप्त नहीं होता है)। –

0

मुझे लगता है कि आप 'काम' और 'क्रैशिंग' संस्करणों के बीच तुलना कर सकते हैं - खुली फ़ाइल डिस्क्रिप्टर और सिग्नल हैंडलर - क्योंकि ये निष्पादन द्वारा पारित होते हैं।

मैं नहीं देख सकता कि वे समस्या कैसे हैं/अलग हैं, लेकिन यह उन्हें समाप्त करने लायक हो सकता है।

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