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