मेरे पास कुछ सी ++ कोड (किसी और द्वारा लिखा गया) है जो गलत फ़ंक्शन को कॉल कर रहा है। यहां स्थिति है:सी ++ किसी ऑब्जेक्ट की पूरी तरह गलत (वर्चुअल) विधि को कॉल करना
UTF8InputStreamFromBuffer* cstream = foo();
wstring fn = L"foo";
DocumentReader* reader;
if (a_condition_true_for_some_files_false_for_others) {
reader = (DocumentReader*) _new GoodDocumentReader();
} else {
reader = (DocumentReader*) _new BadDocumentReader();
}
// the crash happens inside the following call
// when a BadDocumentReader is used
doc = reader->readDocument(*cstream, fn);
जिन फ़ाइलों के लिए शर्त सही है, वे ठीक से संसाधित होते हैं; जिनके लिए यह झूठी दुर्घटना है। DocumentReader के लिए वर्ग पदानुक्रम इस तरह दिखता है:
class GenericDocumentReader {
virtual Document* readDocument(InputStream &strm, const wchar_t * filename) = 0;
}
class DocumentReader : public GenericDocumentReader {
virtual Document* readDocument(InputStream &strm, const wchar_t * filename) {
// some stuff
}
};
class GoodDocumentReader : public DocumentReader {
Document* readDocument(InputStream & strm, const wchar_t * filename);
}
class BadDocumentReader : public DocumentReader {
virtual Document* readDocument(InputStream &stream, const wchar_t * filename);
virtual Document* readDocument(const LocatedString *source, const wchar_t * filename);
virtual Document* readDocument(const LocatedString *source, const wchar_t * filename, Symbol inputType);
}
निम्नलिखित भी प्रासंगिक हैं:
class UTF8InputStreamFromBuffer : public wistringstream {
// foo
};
typedef std::basic_istream<wchar_t> InputStream;
एक विज़ुअल सी में चल रहा है ++ डीबगर, यह पता चलता है कि एक BadDocumentReader पर readDocument कॉल
नहीं बुला रहा हैreadDocument(InputStream&, const wchar_t*)
बल्कि
readDocument(const LocatedString* source, const wchar_t *, Symbol)
यह सभी पठन दस्तावेज़ों में कोउट स्टेटमेंट चिपके हुए द्वारा पुष्टि की जाती है। कॉल के बाद स्रोत तर्क निश्चित रूप से कचरे से भरा होता है, जो जल्द ही दुर्घटना का कारण बनता है। इनस्ट्रिंग में इनपुटस्ट्रीम से एक-तर्क निहित कन्स्ट्रक्टर होता है, लेकिन एक कोउट के साथ जांच से पता चलता है कि इसे कॉल नहीं किया जा रहा है। कोई विचार क्या यह समझा सकता है?
संपादित करें: अन्य संभवतः प्रासंगिक विवरण: दस्तावेज़ रीडर कक्षा कॉलिंग कोड की तुलना में एक अलग पुस्तकालय में हैं। मैंने सभी कोड का पूर्ण पुनर्निर्माण भी किया है और समस्या बनी रही है।
संपादित 2: मैं विज़ुअल सी ++ 2008
संपादित 3 उपयोग कर रहा हूँ: मैं एक ही व्यवहार के साथ एक "न्यूनतम compilable उदाहरण" बनाने की कोशिश की है, लेकिन समस्या को दोहराने में असमर्थ था।
संपादित 4:
बिली ONeal के सुझाव पर, मैं BadDocumentReader शीर्षक में readDocument तरीकों में से आदेश को बदलने की कोशिश की। निश्चित रूप से, जब मैं आदेश बदलता हूं, तो यह बदलता है कि कौन से कार्यों को बुलाया जाता है। ऐसा लगता है कि मेरे संदेह की पुष्टि करने के लिए vtable में अनुक्रमण के साथ कुछ अजीब चल रहा है, लेकिन मुझे यकीन नहीं है कि इसका क्या कारण है।
संपादित 5: यहाँ से पहले समारोह कॉल कुछ लाइनों के लिए disassembly है:
00559728 mov edx,dword ptr [reader]
0055972E mov eax,dword ptr [edx]
00559730 mov ecx,dword ptr [reader]
00559736 mov edx,dword ptr [eax]
00559738 call edx
मैं बहुत विधानसभा पता नहीं है, लेकिन जैसे कि यह पाठक चर सूचक dereferencing है यह मेरे लिए लग रहा है। स्मृति के इस हिस्से में संग्रहीत पहली चीज़ vtable के सूचक होने चाहिए, इसलिए यह eax में dereferences। फिर यह edx में vtable में पहले चीज़ रखता है और इसे कॉल करता है। विधियों के विभिन्न आदेशों के साथ पुन: संकलित करना इसे बदलना प्रतीत नहीं होता है। यह हमेशा vtable में पहली बात कॉल करना चाहता है। (मैं पूरी तरह से गलत समझा सकता था, असेंबली का कोई ज्ञान नहीं था ...)
आपकी मदद के लिए धन्यवाद।
संपादित करें 6: मुझे समस्या मिली, और मैं हर किसी के समय को बर्बाद करने के लिए क्षमा चाहता हूं।समस्या यह थी कि GoodDocumentReader को दस्तावेज़ रीडर के उप-वर्ग के रूप में घोषित किया जाना था, लेकिन वास्तव में नहीं था। सी-स्टाइल कास्ट संकलक त्रुटि को दबा रहा था (आपको सुनना चाहिए था, @ sellibitze, अगर आप एक उत्तर के रूप में अपनी टिप्पणी जमा करना चाहते हैं, तो मैं इसे सही के रूप में चिह्नित करूंगा)। मुश्किल बात यह है कि कोड कई दुर्घटनाओं तक शुद्ध दुर्घटना से काम कर रहा था जब तक किसी ने संशोधन नहीं किया, जब किसी ने गुड डॉक्यूमेंट रीडर को दो और वर्चुअल फ़ंक्शंस जोड़े, तो यह अब भाग्य से सही कार्य नहीं कर रहा था।
'DefaultDocumentReader' क्या है? –
क्या आप इसे कम से कम संकलित करने योग्य उदाहरण में घटा सकते हैं जो इस मुद्दे को प्रदर्शित करता है? –
ओली: क्षमा करें, यह "BadDocumentReader" होना चाहिए। मैंने पोस्ट अपडेट किया है। –