2012-06-08 6 views
14

मैं जेपीईजी छवियों को सहेजने के लिए अभी libjpeg का उपयोग कर रहा हूं। अगर कोई त्रुटि है, तो libjpeg का डिफ़ॉल्ट व्यवहार exit() पर कॉल करना है, जिसे मैं टालना चाहता हूं क्योंकि यह मेरे प्रोग्राम के लिए घातक त्रुटि नहीं है। libjpeg allows you to use your own error manager, और यह आदेश देता है कि यदि आप अपने error_exit() फ़ंक्शन का उपयोग करते हैं (जो डिफ़ॉल्ट रूप से exit() पर कॉल करता है) तो आप कॉलर पर नियंत्रण वापस नहीं कर सकते हैं। libjpeg इस आवश्यकता को पूरा करने के लिए setjmp.h का उपयोग करने का सुझाव देता है और exit() प्रोग्राम नहीं।सी कॉलबैक में सी ++ में अपवाद फेंकना, संभवतः गतिशील लाइब्रेरी सीमा पार करना ... क्या यह सुरक्षित है?

हालांकि, मैं एक सी ++ प्रोग्राम लिख रहा हूं, और मेरे पास अपवादों तक पहुंच है। This question's answer कॉलबैक से अपवाद फेंकने के लिए यह सुरक्षित है (जैसा कि अच्छी तरह से परिभाषित व्यवहार में है)। लेकिन इसमें गतिशील पुस्तकालयों का उल्लेख नहीं है, और अंगूठे का एक सामान्य नियम है कि आप गतिशील पुस्तकालय सीमाओं में अपवाद नहीं फेंकते हैं।

#include <iostream> 
#include <jpeglib.h> 
#include <cstdio> 
#include <stdexcept> 

static void handleLibJpegFatalError(j_common_ptr cinfo) 
{ 
    (*cinfo->err->output_message)(cinfo); 
    throw std::runtime_error("error in libjpeg, check stderr"); 
} 

int main() 
{ 
    struct jpeg_compress_struct cinfo; 
    struct jpeg_error_mgr jerr; 
    FILE* file = std::fopen("out.jpeg", "wb"); // assume this doesn't fail for this example 

    try 
    { 
     cinfo.err = jpeg_std_error(&jerr); 
     jerr.error_exit = handleLibJpegFatalError; 

     // let's say this triggers a fatal error in libjpeg and handleLibJpegFatalError() is called 
     // by libjpeg 
     jpeg_create_compress(&cinfo); 
    } 
    catch (...) 
    { 
     std::cerr << "Error saving the JPEG!\n"; 
    } 

    jpeg_destroy_compress(&cinfo); 
    std::fclose(file); 
} 

मुझे पता है कि क्या करना चाहेंगे है:

यहाँ एक उदाहरण है, भले ही libjpeg एक गतिशील पुस्तकालय के रूप में संकलित किया गया है मैं इस कॉलबैक से एक अपवाद फेंक, और अपने आवेदन में इसे वापस पकड़ कर सकते हैं, ? libjpeg एक स्थैतिक या गतिशील पुस्तकालय हो सकता है, और यदि यह एक गतिशील पुस्तकालय है तो यह संभवतः एक अलग कंपाइलर के साथ बनाया जा सकता है। हालांकि, जो कोड फेंकता है और अपवाद को पकड़ता है वह निश्चित रूप से एक ही संकलन इकाई में होगा। उपरोक्त कोड सुरक्षित है?

FYI करें, मैं ओएस एक्स और Windows के लिए विकसित कर रहा हूँ (और मन में एक लिनक्स संभावना के भविष्य रखने), तो मैं अधिक इच्छुक हूँ में यह सामान्य रूप में अच्छी तरह से परिभाषित व्यवहार, और नहीं माना जाता है, तो एक विशिष्ट मंच/कंपाइलर के लिए।

+0

यह पूरी तरह से सुरक्षित है। ऐसा क्यों नहीं होगा? साझा लाइब्रेरी कॉल अभी भी एक ही कॉल स्टैक का उपयोग करते हैं। –

+1

यह संबंधित हो सकता है: http: // stackoverflow।कॉम/प्रश्न/10318363/यह-सुरक्षित-के-एक्स-त्रुटि-हैंडलर-टू-फेंक-अपवाद – Pubby

+1

@nw: मैं नहीं सोच सकता कि यह क्यों बचाया नहीं जाएगा; मैं सिर्फ यह सुनिश्चित करना चाहता हूं कि ढेर को अनदेखा करते समय कुछ भी ट्रैश नहीं होगा। यह पूरी तरह से सुरक्षित हो सकता है, लेकिन मुझे अतीत में चीजों को मानकर बट में काट दिया गया है, इसलिए मैं इसे यहां सुरक्षित और डबल चेकिंग कर रहा हूं। – Cornstalks

उत्तर

4

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

आप प्रलेखन का पालन करें और setjmp/longjmp का उपयोग सिर्फ कॉल कोड libjpeg के बाहर पाने के लिए करना चाहिए, तो एक अपवाद तुरंत if (setjmp(...)) { ... } शरीर में आप अपवाद उपयोग करना चाहते हैं फेंक देते हैं।

+0

क्या आप लाइब्रेरी कॉल श्रृंखला के भीतर फ्रेम को अनदेखा करने के बारे में बात कर रहे हैं? वे 'सेटजंप' के साथ अवांछित नहीं होंगे, या तो। सी कोड को विशेष रूप से एसईएच फ्रेम/.eh_frame/आदि को आपके सी ++ कॉल के लिए अनचाहे गड़बड़ करने के लिए ओवरराइट करना होगा, जो तब तक नहीं होगा जब तक कोई जानबूझकर गड़बड़ करने की कोशिश नहीं कर रहा था। –

+0

कॉलबैक में अपवाद फेंकना सुरक्षित नहीं है जब तक कि इसे कॉलबैक में भी संभाला नहीं जाएगा। यह कहां/कैसे विफल हो सकता है, यदि सी लाइब्रेरी कोड में बिल्कुल जानकारी नहीं है (कोई '.eh_frame') नहीं है और फ्रेम पॉइंटर्स का उपयोग नहीं करता है, तो सी कोड से परे पीछे हटने का कोई तरीका नहीं है और इसका अर्थ है पहले कॉलफ्रेम जहां अपवाद को संभाला जाना चाहिए। –

4

दूसरा उत्तर यहां लागू होता है। ढेर को अनदेखा करते समय कुछ भी ट्रैश नहीं होगा। इससे कोई फर्क नहीं पड़ता कि पुस्तकालय आंतरिक रूप से कुछ पागल कॉलिंग सम्मेलन का उपयोग करता है, जब तक कि यह आपके सी ++ कार्यान्वयन के अपवाद हैंडलिंग संरचनाओं (जो कि सी प्रोग्राम के रूप में नहीं है) के साथ विशेष रूप से गड़बड़ नहीं करता है। कोई सी ++ कार्यान्वयन जिसे मैं जानता हूं, स्टैक फ्रेम (जो ऑप्टिमाइज़ेशन को एक दुःस्वप्न बनाता है) को पॉप करके कैच ब्लॉक पाता है, वे सभी अपवाद हैंडलिंग के लिए आंतरिक संरचनाओं को बनाए रखते हैं। जब तक कॉल श्रृंखला में कॉल कम हो जाता है, तब तक उन संरचनाओं के साथ गड़बड़ नहीं होती है, अवांछित ढेर आपके सभी व्यक्तिगत कोड के लिए पूरी तरह ठीक काम करेंगे। अब, सामान्य रूप से, यह काफी संभव है कि यह एक गड़बड़ आंतरिक स्थिति के साथ एक लाइब्रेरी छोड़ देगा क्योंकि आप कभी भी क्लीनअप के लिए लाइब्रेरी में निष्पादन वापस नहीं करते हैं, लेकिन आपकी त्रुटि कॉलबैक के मामले में, libjpeg नियंत्रण प्रवाह के लिए वापस आने की अपेक्षा करता है और उसके पास है संभवतः पहले से ही साफ हो गया है।

इस मामले में, मैं इसके लिए जाऊंगा। आम तौर पर, मैं केवल सी कॉलबैक से घातक अपवाद फेंक दूंगा।

आशा है कि इससे मदद मिलेगी।

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