UBSan & Clang’s Указатель на функцию: это незаконно?

Я пытаюсь вызвать некоторые функции C ++ через таблицу указателей на функции, которая экспортируется как символ C из общего объекта. Код на самом деле работает, но неопределенное дезинфицирующее средство для поведения Clang (= 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

Из-за неопределенного дезинфицирующего поведения Clang допустимо косвенно вызывать функцию, которая возвращает ссылку на объект стандартного класса C ++ через указатель на функцию но это недопустимо для определенного пользователем класса. Кто-нибудь, не могли бы вы сказать мне, что с ним не так?

Я пытался построить проект на Убунту 14.04 с Clang-llvm 3.4-1ubuntu3 а также CMake 2.8.12.2. Чтобы воспроизвести это явление, пожалуйста, разместите 5 файлов в том же каталоге и вызвать build.sh. Он создаст make-файл, соберет проект и запустит исполняемый файл.

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

Я пытался найти ключ, чтобы разобраться в проблеме, и понял, что проблема была обнаружена опцией «function» sanitizer (-fsanitize = function), но это не так много задокументировано. Я был бы признателен, если бы вы, ребята, смогли дать мне разумное объяснение такого сообщения об ошибке во время выполнения, которое выглядит как пришедшее с другой планеты. Благодарю.

На что Clang указал как «неизвестный» в выводе?

Ниже приведен вывод addr2line для проверки того, что было «неизвестно» для дезинфицирующего средства:

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

Хм, это действительно похоже на функцию, которую я ожидал вызвать для меня. Можете ли вы догадаться, как это выглядело иначе для Clang?

10

Решение

сантибар-х typeinfo должен иметь видимость по умолчанию для типа функции, которую Clang рассматривает в Linux одинаково для исполняемого файла и динамической библиотеки; изменить Foo.h на:

  class EXPORT CBar
{
...
}
7

Другие решения


По вопросам рекламы [email protected]