10

我正在尝试通过函数指针表调用一些 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++ 标准类对象的引用的函数是合法的,但对于用户定义的类是非法的。有人能告诉我它有什么问题吗?

我一直在尝试使用Clang-llvm 3.4-1ubuntu3CMake 2.8.12.2在Ubuntu 14.04上构建项目。要重现该现象,请将以下5个文件放在同一目录下并调用build.sh。它将创建一个 makefile 并构建项目,并运行可执行文件。

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,
    };
}

你好世界.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)

构建.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

我一直在试图找到一个线索来深入研究这个问题,并意识到这个问题是由消毒剂的“功能”选项(-fsanitize=function)发现的,但它没有太多的记录。如果你们能给我一个合理的解释,我会很感激这样一个运行时错误消息,它看起来像是来自另一个星球。谢谢。

Clang 在输出中指出的“未知”是什么?

下面是 addr2line 的输出,用于检查消毒剂的“未知”内容:

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

嗯,它真的看起来像我期待调用的函数。你能猜到 Clang 看起来有什么不同吗?

4

1 回答 1

8

CBartypeinfo需要具有函数类型的默认可见性,这在 Linux 上的 Clang 跨可执行文件和动态库被认为是相同的;将 Foo.h 更改为:

  class EXPORT CBar
  {
      ...
  }
于 2015-01-19T09:16:03.430 回答