2015-02-16 8 views
6

मैं सिस्टम फ़ंक्शन open() पर एक हुक बनाने की कोशिश कर रहा हूं। मैंने इसे निम्नलिखित पंक्तियों के साथ किया है।खुले से हुक से सेगमेंटेशन गलती()

extern int mocked_open(const char* fn, int flags, va_list args); 

int open(const char* fn, int flags, ...) 
{ 
    int r = -1; 
    va_list args; 

    va_start(args, flags); 
    r = mocked_open(fn, flags, args); 
    va_end(args); 

    return r; 
} 

मैं libwrapper.so में इस संकलन है, जो मैं LD_PRELOAD का उपयोग करके लोड:

मैं निम्नलिखित के साथ एक आवरण पुस्तकालय बनाया।

int mocked_open(const char* fn, int flags, va_list args) 
{ 
    if (strncmp(fn, test_device_id, 11) == 0) 
    { 
     return mock().actualCall("open").returnValue().getIntValue(); 
    } 
    else 
    { 
     int r = -1; 
     int (*my_open)(const char*, int, ...); 
     void* fptr = dlsym(RTLD_NEXT, "open"); 
     memcpy(&my_open, &fptr, sizeof(my_open)); 

     if (flags & O_CREAT) 
     { 
      r = my_open(fn, flags, va_arg(args, mode_t)); 
     } 
     else 
     { 
      r = my_open(fn, flags); 
     } 

     return r; 
    } 
} 

test_device_id एक सरल स्ट्रिंग ("test_device"), जो मुझे आशा है कि अन्यत्र इस्तेमाल नहीं किया जाता है:

mocked_open() के कार्यान्वयन के रूप में इस प्रकार है (मैं CPPUtest ढांचे का उपयोग) है।

परीक्षण चलाने के दौरान निष्पादन योग्य एक खंडन गलती के साथ दुर्घटनाग्रस्त हो जाता है। मैंने इसे जीसीसी प्रोफाइलिंग कार्यक्षमता में खोज लिया है, जो .gcda फ़ाइलों का एक गुच्छा खोलना/बनाना चाहता है और इसके लिए open() पर कॉल करना चाहता है।

स्ट्रेस (नीचे प्रति सुझाव) के साथ कुछ डिबगिंग के बाद, मैंने पाया कि लाइन r = my_open(fn, flags, va_arg(args, mode_t)); वास्तव में अपराधी है। इसे रिकर्सिवली कहा जा रहा है, या ऐसा लगता है: फ़ंक्शन लौटने के बिना, मुझे इस लाइन में बहुत सी कॉल दिखाई देती हैं। फिर एक segfault। खोला जा रहा फ़ाइल संबंधित .gcda फ़ाइल (प्रोफाइलिंग के लिए) है। वास्तव में, segfault केवल प्रोफाइलिंग प्रोफाइलिंग के साथ होता है।

+0

मुझे लगता है कि आपकी समस्या भिन्न हैंडलिंग http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c – user590028

+0

@ user590028: क्या आप विस्तारित कर सकते हैं? मैंने सोचा कि विविध तर्क प्रबंधन के साथ कुछ गड़बड़ है (जैसा कि मैंने लिखा है), लेकिन क्या ...? – Ludo

+1

आपके परीक्षण-मामलों पर 'ओपन() '' स्ट्रेस' शो' किस प्रकार की कॉल का उपयोग किया जाता है? – alk

उत्तर

4

के लिए जब आप सक्षम gcov रूपरेखा के साथ संकलन उम्मीद है, संकलक अपने कार्यों में अतिरिक्त कोड सम्मिलित करता है, ट्रैक जिनमें से कोड निष्पादित कर दिया गया है रखने के लिए। किसी न किसी तरह स्यूडोकोड में, कि डाला कोड (अन्य बातों के अलावा) करना होगा:

if (!output_file_has_been_opened) { 
    fd = open(output_filename, ...); 
    check_ok(fd); 
    output_file_has_been_opened = TRUE; 
    track_coverage(); 
} 

... इसलिए यदि आउटपुट फ़ाइल अभी तक सफलतापूर्वक नहीं खोला गया है (अपने कार्यक्रम के शुरू में के रूप में), यह प्रयास करेंगे इसे खोलने के लिए। दुर्भाग्यवश, इस मामले में जो आपके मॉक open() फ़ंक्शन को कॉल करेगा - जिसमें एक ही डाला गया कोड होगा; चूंकि फ़ाइल अभी भी सफलतापूर्वक खोला नहीं गया है, और चूंकि gcov कोड को पता नहीं है कि कुछ असामान्य चल रहा है, यह open() फिर से कॉल करने का प्रयास करेगा - और यही कारण है कि रिकर्सन (और आखिरकार segfault, एक बार ढेर थका हुआ है)।

+0

हम्म, मुझे लगता है स्पष्टीकरण कुछ हद तक अधूरा होना चाहिए, क्योंकि आम तौर पर gcov फ़ाइल को खोलने का प्रयास करेगा जब यह अपना आउटपुट लिखता है - उदाहरण के लिए जब कोई प्रोग्राम निकलता है, लेकिन कुछ अन्य समय भी। कुछ .gcda फ़ाइल लिखने के लिए इसे ट्रिगर करना चाहिए (इसलिए आप इसे क्यों खोल रहे हैं), लेकिन यह अभी मुझे स्पष्ट नहीं है कि यह क्या है ... – psmears

+0

यह स्पष्टीकरण मेरे लिए बेहद व्यावहारिक लगता है और सुसंगत है मेरे अवलोकन के साथ। मैं gcda फ़ाइल खोलने के लिए 'ओपन' पर कॉल देखता हूं _after_ मेरे परीक्षण पूरा हो गए हैं। मुझे यकीन नहीं है कि सीपीपीयूटीएस्ट के पास कितना टियरडाउन कोड है, लेकिन जहां तक ​​मैं कह सकता हूं, कार्यक्रम निष्पादन के अंत में कॉल बहुत अधिक हैं। आपकी स्पष्टीकरण हालांकि यह भी दर्शाती है कि मैं प्रोफाइलिंग सक्षम के साथ 'ओपन()' पर एक हुक नहीं डाल सकता ... – Ludo

+0

@ लुडो: धन्यवाद! ईमानदार होने के लिए मुझे अभी भी लगता है कि जिग्स का एक टुकड़ा गुम है: यह मुझे स्पष्ट नहीं है कि gcov सामान को अपनी फाइल लिखने का कारण क्या है। अगर हम इसे समझ सकते हैं, तो प्रोफाइलिंग सक्षम के साथ 'ओपन()' हुक रखने का एक तरीका हो सकता है। क्या जीडीबी सेगमेंटेशन गलती के लिए सार्थक स्टैक ट्रेस देता है? किसी भी मामले में, एक वर्कअराउंड हो सकता है (यदि आपका बिल्ड सिस्टम इसे अनुमति देता है) प्रोफाइलिंग के बिना एलडी_PRELOAD लाइब्रेरी को संकलित करने के लिए, लेकिन शेष कोड के साथ - आपको टेस्ट लाइब्रेरी के लिए gcov डेटा नहीं मिलेगा, लेकिन संभवतः यह कम महत्वपूर्ण है परीक्षण के तहत कोड के लिए? – psmears

5

इस

typedef int (*OpenFunction)(const char* fn, int flags, ...); 

प्रयास करें तो

OpenFunction function; 
void  **pointer; 

pointer = (void **)&function; 
*pointer = dlsym(RTLD_NEXT, "open"); 

इस एक पूरा काम कर उदाहरण

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <dlfcn.h> 
#include <unistd.h> 
#include <fcntl.h> 

#include <errno.h> 

typedef int (*OpenFunction)(const char* fn, int flags, ...); 

int main(int argc, char **argv) 
{ 
    OpenFunction function; 
    void  *dl; 
    int   fd; 
    void  **pointer; 

    if (argc < 2) 
     return -1; 
    pointer = (void **)&function; 
    *pointer = dlsym(RTLD_NEXT, "open"); 

    fd = function(argv[1], O_RDONLY); 
    if (fd != -1) 
    { 
     printf("file opened succesfully\n"); 
     close(fd); 
    } 
    else 
    { 
     printf("%s: cannot open the file\n", strerror(errno)); 
    } 
    return 0; 
} 
+0

मैंने यहां पढ़ा है (http://stackoverflow.com/questions/10519312/how-does-this-make-sense-void-fptr-dlsymhandle-my- कार्यक्षमता) कि इस तरह के कलाकारों का उपयोग विशेष रूप से अनुशंसित नहीं किया गया था। – Ludo

+1

रिकॉर्ड के लिए: फ़ंक्शन पॉइंटर प्राप्त करने के लिए आपके दृष्टिकोण का उपयोग करने से कोई फर्क नहीं पड़ता है, मुझे अभी भी सेगमेंटेशन गलती मिलती है। – Ludo

+0

@ लुडो मैंने इसेस्ट में पसंद नहीं किया है, और चूंकि आप अभी भी सेगमेंटेशन गलती प्राप्त कर रहे हैं, समस्या कुछ अन्य समस्या है, क्योंकि उदाहरण सही तरीके से काम करता है। –

0

आप va_list गलत तरीके से गुजर रहे हैं। निम्नलिखित का प्रयास करें यह मदद करता है

 r = my_open(fn, flags, args); 

अधिक जानकारी http://c-faq.com/varargs/handoff.html

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