2015-01-16 15 views
10

मैं कुछ सी ++ फ़ंक्शन को फ़ंक्शन पॉइंटर टेबल के माध्यम से कॉल करने का प्रयास कर रहा हूं जिसे किसी साझा ऑब्जेक्ट से सी प्रतीक के रूप में निर्यात किया जाता है। कोड वास्तव में काम कर रहा है लेकिन प्रक्षालक (= UBSan) बजना के अपरिभाषित व्यवहार देखता कॉल मैंने बनाया अवैध इस प्रकार है:क्लैंग का यूब्सन और फ़ंक्शन पॉइंटर: क्या यह अवैध है?

==11410==WARNING: Trying to symbolize code, but external symbolizer is not initialized! 
path/to/HelloWorld.cpp:25:13: runtime error: call to function (unknown) through pointer to incorrect function type 'foo::CBar &(*)()' 
(./libFoo.so+0x20af0): note: (unknown) defined here 

प्रक्षालक बजना के अपरिभाषित व्यवहार के कारण, यह कानूनी है परोक्ष रूप से एक समारोह जो एक संदर्भ रिटर्न कॉल करने के लिए एक फंक्शन पॉइंटर के माध्यम से एक सी ++ मानक वर्ग ऑब्जेक्ट का, लेकिन यह उपयोगकर्ता द्वारा परिभाषित वर्ग के लिए अवैध है। कोई आप कृपया मुझे बता सकता है कि इसमें क्या गलत है?

मैं साथ बजना-LLVM 3.4-1ubuntu3 और CMake 2.8.12.2Ubuntu 14.04 पर परियोजना बनाने की कोशिश कर रहा हूँ। घटना को पुन: पेश करने के लिए, कृपया उसी निर्देशिका में निम्नलिखित 5 फ़ाइलें रखें और build.sh का आह्वान करें। यह एक मेकफ़ाइल बनायेगा और प्रोजेक्ट का निर्माण करेगा, और निष्पादन योग्य चलाएगा।

Foo.h

#ifndef FOO_H 
#define FOO_H 

#include <string> 

// 
#define EXPORT __attribute__ ((visibility ("default"))) 

namespace foo { 
    class CBar 
    { 
     // empty 
    }; 

    class CFoo 
    { 
    public: 
     static CBar& GetUdClass(); 
     static std::string& GetStdString(); 
    }; 

    // function pointer table. 
    typedef struct 
    { 
     CBar& (*GetUdClass)(); 
     std::string& (*GetStdString)(); 
    } fptr_t; 

    //! function pointer table which is exported. 
    extern "C" EXPORT const fptr_t FptrInFoo; 
} 

#endif 

Foo.cpp

#include "Foo.h" 
#include <iostream> 

using namespace std; 

namespace foo 
{ 
    // returns reference of a static user-defined class object. 
    CBar& CFoo::GetUdClass() 
    { 
     cout << "CFoo::GetUdClass" << endl; 
     return *(new CBar); 
    } 

    // returns reference of a static C++ standard class object. 
    std::string& CFoo::GetStdString() 
    { 
     cout << "CFoo::GetStdString" << endl; 
     return *(new string("Hello")); 
    } 

    // function pointer table which is to be dynamically loaded. 
    const fptr_t FptrInFoo = { 
     CFoo::GetUdClass, 
     CFoo::GetStdString, 
    }; 
} 

HelloWorld.cpp

#include <iostream> 
#include <string> 
#include <dirent.h> 
#include <dlfcn.h> 
#include "Foo.h" 

using namespace std; 
using namespace foo; 

int main() 
{ 
    // Retrieve a shared object. 
    const string LibName("./libFoo.so"); 
    void *pLibHandle = dlopen(LibName.c_str(), RTLD_LAZY); 
    if (pLibHandle != 0) { 
     cout << endl; 
     cout << "Info: " << LibName << " found at " << pLibHandle << endl; 
     // Try to bind a function pointer table: 
     const string SymName("FptrInFoo"); 
     const fptr_t *DynLoadedFptr = static_cast<const fptr_t *>(dlsym(pLibHandle, SymName.c_str())); 
     if (DynLoadedFptr != 0) { 
      cout << "Info: " << SymName << " found at " << DynLoadedFptr << endl; 
      cout << endl; 
      // Do something with the functions in the function table pointer. 
      DynLoadedFptr->GetUdClass(); // Q1. Why Clang UBSan find this is illegal?? 
      DynLoadedFptr->GetStdString(); // Q2. And why is this legal?? 
     } else { 
      cout << "Warning: Not found symbol" << endl; 
      cout << dlerror() << endl; 
     } 
    } else { 
     cout << "Warning: Not found library" << endl; 
     cout << dlerror() << endl; 
    } 
    cout << endl; 
    return 0; 
} 

CMakeLists.txt

project (test) 

if(COMMAND cmake_policy) 
     cmake_policy(SET CMP0003 NEW) 
endif(COMMAND cmake_policy) 

set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,$ORIGIN") 

add_library(Foo SHARED Foo.cpp) 

add_executable(HelloWorld HelloWorld.cpp) 
target_link_libraries (HelloWorld dl) 

build.sh

#!/bin/bash 

# 1. create a build directory. 
if [ -d _build ]; then 
    rm -rf _build 
fi 
mkdir _build 
cd _build 

# 2. generate a makefile. 
CC=clang CXX=clang++ CXXFLAGS="-fvisibility=hidden -fsanitize=undefined -O0 -g3" cmake .. 

# 3. build. 
make 

# 4. and run the executable. 
./HelloWorld 

मैं इस मुद्दे में खुदाई करने के लिए एक सुराग खोजने की कोशिश कर रहा है और महसूस किया मुद्दे के "समारोह" विकल्प द्वारा पकड़ा गया था sanitizer (-fsanitize = समारोह) लेकिन यह इतना दस्तावेज नहीं है। मैं सराहना करता हूं अगर आप मुझे ऐसे रनटाइम त्रुटि संदेश के लिए उचित स्पष्टीकरण दे सकते हैं जो किसी अन्य ग्रह से आने जैसा दिखता है। धन्यवाद।

क्लैंग आउटपुट में "अज्ञात" के रूप में क्या इंगित कर रहा था?

$ addr2line -Cfe _build/libFoo.so 0x20af0 
foo::CFoo::GetUdClass() 
path/to/Foo.cpp:12 

हम्म, यह वास्तव में समारोह मैं मेरे लिए कॉल करने के लिए उम्मीद कर रहा था की तरह लग रहा:

नीचे क्या प्रक्षालक के लिए "अज्ञात" था की जांच करने के addr2line से उत्पादन होता है। क्या आप अनुमान लगा सकते हैं कि यह क्लैंग के लिए अलग कैसे दिखता है?

+0

'FptrInFoo' नामस्थान' foo' में फ़ंक्शन पॉइंटर नहीं है, यह एक वैश्विक है! साधारण कारण यह है कि इसे 'बाहरी' सी ''के रूप में घोषित किया जाता है। एक अलग नामस्थान में घोषित करने का प्रयास करें और आप देखेंगे।अब मैं सोच रहा हूं कि परिभाषा नामस्थान के अंदर एक वस्तु बनायेगी (और स्थैतिक संबंध के साथ, क्योंकि यह स्थिर है) या यदि यह बाहरी वैश्विक को परिभाषित करता है। बीटीडब्ल्यू: आप "टाइपपीफ स्ट्रक्चर ..." का उपयोग क्यों कर रहे हैं, आप वैसे भी उस कोड का उपयोग सी में नहीं कर सकते हैं। –

उत्तर

7

सीबीर के typeinfo को फ़ंक्शन के प्रकार के लिए डिफ़ॉल्ट दृश्यता की आवश्यकता होती है जिसे निष्पादन योग्य और गतिशील लाइब्रेरी में लिनक्स पर क्लैंग द्वारा समान माना जाता है; Foo.h को बदलें:

class EXPORT CBar 
    { 
     ... 
    } 
+0

गंदा। मुझे आश्चर्य है कि बेहतर डायग्नोस्टिक प्रदान करने के लिए कंपाइलर को बेहतर किया जा सकता है या नहीं। अच्छी पकड़ स्टीफन! –

+0

चूंकि मैंने इस पर कुछ घंटों खो दिए हैं, इसलिए मैं इसे जोड़ सकता हूं कि '__attribute__ ((दृश्यता ("डिफ़ॉल्ट")) (' लाइब्रेरी में और निष्पादन योग्य दोनों में इसका उपयोग करने के लिए सावधान रहना चाहिए। – Arnaud

+0

यदि सीबीर 'पॉलिमॉर्फिक नहीं है तो यह पर्याप्त नहीं लगता है। मुझे 'शून्य (कुछ ईनम, कॉन्स कुछस्ट्रक्चर और कॉन्स कुछ क्लास और) पर समस्या है। इनमें से कोई भी प्रकार पॉलिमॉर्फिक नहीं है, इसलिए मुझे नहीं लगता कि इनमें से किसी भी प्रकार के आरटीटीआई को कंपाइलर द्वारा उत्सर्जित किया जाएगा। ऐसा लगता है कि यह डुप्लिकेट टाइप_इनफोस से गुजरता है उसी तरह इनलाइन अपवाद वर्ग सिरदर्द का कारण बनता है: https://marcmutz.wordpress.com/2010/08/04/fun-with-exceptions/ –

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