2011-06-24 14 views
11

मैं एक ऐसे प्रोजेक्ट पर काम कर रहा हूं जो बहुत अधिक थ्रेडेड है, और यह सोच रहा था कि कंपाइलर को सी लाइब्रेरी में गैर-पुनर्वित्त कॉल का उपयोग करने का कोई तरीका है (उदाहरण के लिए strtok_r का strtok intsead)? यदि नहीं, तो क्या कॉल की एक सूची है जो गैर-पुनर्वित्तक है इसलिए मैं समय-समय पर अपने कोड आधार के माध्यम से grep कर सकता हूं?क्या गैर-पुनर्विक्रेता सी लाइब्रेरी कॉल के उपयोग को ध्वजांकित करने का कोई तरीका है?

एक संबंधित प्रश्न यह है कि अगर 3 डी पार्टी लाइब्रेरी गैर-पुनर्वित्त कॉल के उपयोग को ध्वजांकित करने का कोई तरीका है।

मुझे लगता है कि पुनर्वितरण थ्रेड-सुरक्षा का तात्पर्य है, लेकिन जरूरी नहीं कि अन्य तरीकों से। क्या थ्रेडेड प्रोजेक्ट में गैर-पुनर्वित्त कॉल का उपयोग करने का कोई अच्छा कारण है?

+0

प्रश्न - क्या सभी सी रनटाइम कॉल लिनक्स में हैं जो कॉल के बीच स्थिति बनाए रखती हैं (जैसे मॉलोक, रैंड, स्ट्रोक, इत्यादि ...) स्वाभाविक रूप से गैर-थ्रेडसेफ? या क्या इन कॉल के लिए थ्रेड सुरक्षित संस्करण से लिंक करने के लिए एक कंपाइलर/लिंकर निर्देश है? मैं वास्तव में सोच रहा हूं कि थ्रेड सुरक्षा के लिए हल करने में वास्तव में कोई समस्या है या नहीं। – selbie

+0

@selbie: नहीं, यह भिन्न होता है। उदाहरण के लिए, [malloc] (http://www.bozemanpass.com/info/linux/malloc/Linux_Heap_Contention.html) आमतौर पर थ्रेडसेफ होता है। 'रैंड()' का धागासात्व वैसे भी दार्शनिक प्रश्न है। एक परिपूर्ण 'रैंड' कार्यान्वयन (एक ओरेकल) मूल रूप से थ्रेडसेफ होगा। – MSalters

उत्तर

5

स्रोत के लिए, आप संभवतः जोर देते हैं सकता है कि हर स्रोत फ़ाइल लाइन में शामिल हैं:

#include <beware.h> 
सी हेडर के बाद

, और फिर beware.h हेडर फाइल में शामिल हैं:

#define strtok unsafe_function_call_detected_strtok 
#define getenv unsafe_function_call_detected_getenv 

या कुछ अन्य उपयुक्त उन नामों का सेट जो वास्तविक कार्य होने की संभावना नहीं है। इसके परिणामस्वरूप संकलन और/या लिंकर त्रुटियां होंगी।

पुस्तकालयों के लिए, यह थोड़ा और मुश्किल है। आप प्रत्येक ऑब्जेक्ट फ़ाइल में सभी अनसुलझे नाम निकालने के लिए nm का उपयोग करके देख सकते हैं और सुनिश्चित कर सकते हैं कि असुरक्षित लोगों में से कोई भी नहीं कहा जाता है।

यह ऐसा करने वाला संकलक नहीं होगा लेकिन बिल्ड स्क्रिप्ट में शामिल करना आसान होगा। (और gcc बहुत sneakily के बाद से मैं यह कोई स्वरूपण आदेशों के साथ एक निरंतर स्ट्रिंग दिया printf के बजाय puts उपयोग करने के लिए फैसला किया है)

$ cat qq.c 
    #include <stdio.h> 

    int main (int argc, char *argv[]) { 
     printf ("Hello, world.\n"); 
     return 0; 
    } 

$ gcc -c -o qq.o qq.c 

$ nm qq.o 
00000000 b .bss 
00000000 d .data 
00000000 r .rdata 
00000000 t .text 
     U ___main 
00000000 T _main 
     U _puts 

आप एक U मार्कर के साथ कि उत्पादन में अनसुलझे प्रतीक देख सकते हैं: निम्नलिखित ट्रांसक्रिप्ट देखें ।

+0

हेडर फ़ाइल और एनएम स्क्रिप्ट पर अच्छा विचार। क्या वहां गैर-पुनर्वित्तक सी lib कार्यों की एक सूची है? – Ravi

+0

यदि आप जीसीसी का उपयोग कर रहे हैं, तो आप '# परिभाषित' के बेहतर विकल्प के रूप में '#pragma GCC poison strtok' का उपयोग कर सकते हैं। –

+0

एनएम शैली पर एक संस्करण के रूप में आप इस तरह की फाइल को परिभाषित कर सकते हैं: _checkfns.c_: 'void not_thread_safe(); शून्य रखता है() {not_thread_safe(); } 'फिर यह फ़ंक्शंस के सिस्टम संस्करणों को छुपाएगा और आपको एक त्रुटि मिलेगी:' अपरिभाषित प्रतीकों: "_not_thread_safe", यदि आपने put का उपयोग करने का प्रयास किया है तो _ffsff.o' में संदर्भित किया गया है। (आपको उन मामलों के लिए मृत कोड स्ट्रिपिंग सक्षम करने की आवश्यकता होगी जो इसका उपयोग नहीं करते हैं ... '-Xlinker -dead_strip' मेरे लिए) –

1

अपने प्रश्न के दूसरे भाग को संबोधित करते:

गैर पुन: प्रवेशी कॉल एक तरीका है कि उन्हें एक प्रदर्शन लाभ देता है में लागू किया जा सकता है। इस मामले में यदि आप जानते हैं कि आप केवल उन कॉलों को एक थ्रेड (या एक महत्वपूर्ण खंड में) से बना रहे हैं, और वे आपकी बाधा हैं तो गैर-पुनर्वित्त कॉल का चयन करना समझ में आता है। लेकिन मैं केवल तभी ऐसा करूँगा जब प्रदर्शन माप थे कि यह ऐसा करने के लिए महत्वपूर्ण था ... और ध्यान से इसे दस्तावेज करें ..

0

द्विआधारी के लिए, आप LD_PRELOAD का उपयोग कर सकते हैं जो भी सी लाइब्रेरी फ़ंक्शन आपको पसंद करते हैं और लेते हैं जो भी आप चाहते हैं (निरस्त करें, एक त्रुटि लॉग करें लेकिन आगे बढ़ें, आदि)

विकास के दौरान, आप इसे करने के लिए वालग्रिंड का भी उपयोग कर सकते हैं।

कुछ नमूना कोड और संदर्भ के लिए, how could I intercept linux sys calls?

2

के उत्तर देख में कॉल की सूची है कि गैर रैत्रांत हैं तो मैं समय-समय पर अपना कोड बेस के माध्यम से grep कर सकते हैं?

मैंने जीएनयू libc फ़ंक्शन सूची को देखा, और _r के साथ लोगों को चुना। सूची यहाँ है।

asctime, तहखाने, ctime, drand48, ecvt, एन्क्रिप्ट, erand48, fcvt, fgetgrent, fgetpwent, getdate, getgrent, getgrgid, getgrnam, gethostbyaddr, gethostbyname2, गेथोस्टबाइनेम, getmntent, getnetgrent, getpwent, getpwnam, getpwuid, getutent, Getutid, getutline, gmtime, hcreate, hdestroy, hsearch, initstate, jrand48, lcong48, lgamma, lgammaf, lgammal, localime, lrand48, mrand48, nrand48, ptsname, qecvt, qfcvt, rand, random, readdir64, readdir, seed48, setkey, सेटस्टेट, srand48, srandom, strerror, strtok, tmpnam, ttyname

+0

'readdir_r' पर ध्यान दें: मैनपेज देखें। जीएनयू libc नियमित 'readdir' का उपयोग करने की सिफारिश करता है और' readdir_r' – Dacav

0

Cppcheck गैर-पुनर्वित्त मानक लाइब्रेरी फ़ंक्शंस का उपयोग ध्वजांकित करेगा। इस चेक को सक्षम करने के लिए पोर्टेबिलिटी चेतावनियां सक्षम करें।

कार्यों की सूची के लिए non_reentrant_functions_list in checknonreentrantfunctions.h देखें Cppcheck ध्वजांकित करेगा। संदेश की

उदाहरण Cppcheck फेंकना होगा:

गैर रैत्रांत समारोह 'strtok' कहा जाता है। थ्रेडसेफ अनुप्रयोगों के लिए पुनर्वित्त प्रतिस्थापन फ़ंक्शन 'strtok_r' का उपयोग करने की अनुशंसा की जाती है। (पोर्टेबिलिटी: nonreentrantFunctionsstrtok)

+0

बहिष्कृत करता है जो चेक किए गए कार्यों की सूची अपूर्ण दिखाई देती है। strerror_r() गायब है। अन्य फ़ंक्शन भी हैं (बिना _ प्रत्यय के) जो पुनर्विक्रेता नहीं हैं, जैसे getenv(), system(), और दूसरों का पूरा समूह। यहां सूचीबद्ध करें: [http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_01]। लेकिन यह भी पूरा नहीं है। Setlocale() या किसी अन्य फ़ंक्शन के बारे में सोचें जो प्रक्रिया-व्यापी विशेषता को संशोधित करता है। आप संभावित रूप से विनाश के बिना थ्रेडेड पुस्तकालयों से उनको कॉल नहीं कर सकते हैं। –