Issue |
91248
|
Summary |
Registering Clang plugins on Windows does not work due to different pointers for FrontendPluginRegistry::Head
|
Labels |
clang
|
Assignees |
|
Reporter |
hach-que
|
I built my own version of Clang for Windows that provides the `lib\clang...lib` files for Windows, and then built a Clang plugin against it.
The typical definition doesn't work:
```cpp
static FrontendPluginRegistry::Add<redpoint::AlwaysBeforeAction> X3("redpoint-namespace-warnings", "");
```
so instead I tried registering it through DllMain which *does* successfully run, but the linked lists for `FrontendPluginRegistry` end up different:
```cpp
static FrontendPluginRegistry::Add<redpoint::AlwaysBeforeAction>* RedpointPluginInstance = nullptr;
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved) // reserved
{
// Perform actions based on the reason for calling.
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
printf("dll loaded!\n");
{
if (RedpointPluginInstance == nullptr)
{
printf("registering plugin...\n");
RedpointPluginInstance = new FrontendPluginRegistry::Add<redpoint::AlwaysBeforeAction>("redpoint-namespace-warnings", "");
}
for (const FrontendPluginRegistry::entry& Plugin :
FrontendPluginRegistry::entries()) {
printf("plugin: %s\n", Plugin.getName().str().c_str());
}
}
break;
case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
printf("dll thread attach!\n");
break;
case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
printf("dll thread detach!\n");
break;
case DLL_PROCESS_DETACH:
printf("dll unloaded!\n");
if (lpvReserved != nullptr)
{
break; // do not do cleanup if process termination scenario
}
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
```
I modified `LLVM_INSTANTIATE_REGISTRY` to print out the locations of `Head` and `Tail`:
```cpp
#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
namespace llvm { \
template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
template<typename T> \
void Registry<T>::add_node(typename Registry<T>::node *N) { \
printf("add_node Registry<" #REGISTRY_CLASS ">::Head = (& %p) (v %p)\n", &Head, Head); \
printf("add_node Registry<" #REGISTRY_CLASS ">::Tail = (& %p) (v %p)\n", &Tail, Tail); \
if (Tail) \
Tail->Next = N; \
else \
Head = N; \
Tail = N; \
} \
template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
printf("begin &Registry<" #REGISTRY_CLASS ">::Head = (& %p) (v %p)\n", &Head, Head);\
printf("begin &Registry<" #REGISTRY_CLASS ">::Tail = (& %p) (v %p)\n", &Tail, Tail);\
return iterator(Head); \
} \
template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
template \
void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
}
```
Running Clang with the plugin, then gives the following output:
```
-fplugin=C:\Work\clang-plugins-demo\buildmsvc\lib\Release\streamchecker.dll -Xclang -plugin -Xclang redpoint-namespace-warnings main.cpp -fsyntax-only
add_node Registry<GCRegistry>::Head = (& 00007FF773911230) (v 0000000000000000)
add_node Registry<GCRegistry>::Tail = (& 00007FF773911238) (v 0000000000000000)
add_node Registry<GCRegistry>::Head = (& 00007FF773911230) (v 00007FF77388DD40)
add_node Registry<GCRegistry>::Tail = (& 00007FF773911238) (v 00007FF77388DD40)
add_node Registry<GCRegistry>::Head = (& 00007FF773911230) (v 00007FF77388DD40)
add_node Registry<GCRegistry>::Tail = (& 00007FF773911238) (v 00007FF77388DD78)
add_node Registry<GCRegistry>::Head = (& 00007FF773911230) (v 00007FF77388DD40)
add_node Registry<GCRegistry>::Tail = (& 00007FF773911238) (v 00007FF77388DDB0)
add_node Registry<GCRegistry>::Head = (& 00007FF773911230) (v 00007FF77388DD40)
add_node Registry<GCRegistry>::Tail = (& 00007FF773911238) (v 00007FF77388DDE8)
Plugin to load: C:\Work\clang-plugins-demo\buildmsvc\lib\Release\streamchecker.dll
add_node Registry<GCRegistry>::Head = (& 00007FF93A49EB50) (v 0000000000000000)
add_node Registry<GCRegistry>::Tail = (& 00007FF93A49EB58) (v 0000000000000000)
add_node Registry<GCRegistry>::Head = (& 00007FF93A49EB50) (v 00007FF93A48D0B0)
add_node Registry<GCRegistry>::Tail = (& 00007FF93A49EB58) (v 00007FF93A48D0B0)
add_node Registry<GCRegistry>::Head = (& 00007FF93A49EB50) (v 00007FF93A48D0B0)
add_node Registry<GCRegistry>::Tail = (& 00007FF93A49EB58) (v 00007FF93A48D0E8)
add_node Registry<GCRegistry>::Head = (& 00007FF93A49EB50) (v 00007FF93A48D0B0)
add_node Registry<GCRegistry>::Tail = (& 00007FF93A49EB58) (v 00007FF93A48D120)
add_node Registry<GCRegistry>::Head = (& 00007FF93A49EB50) (v 00007FF93A48D0B0)
add_node Registry<GCRegistry>::Tail = (& 00007FF93A49EB58) (v 00007FF93A48D158)
dll loaded!
registering plugin...
add_node Registry<FrontendPluginRegistry>::Head = (& 00007FF93A493C48) (v 0000000000000000)
add_node Registry<FrontendPluginRegistry>::Tail = (& 00007FF93A493C50) (v 0000000000000000)
begin &Registry<FrontendPluginRegistry>::Head = (& 00007FF93A493C48) (v 000001BC2E2BDAE8)
begin &Registry<FrontendPluginRegistry>::Tail = (& 00007FF93A493C50) (v 000001BC2E2BDAE8)
plugin: redpoint-namespace-warnings
begin &Registry<FrontendPluginRegistry>::Head = (& 00007FF773920540) (v 0000000000000000)
begin &Registry<FrontendPluginRegistry>::Tail = (& 00007FF773920548) (v 0000000000000000)
begin &Registry<FrontendPluginRegistry>::Head = (& 00007FF773920540) (v 0000000000000000)
begin &Registry<FrontendPluginRegistry>::Tail = (& 00007FF773920548) (v 0000000000000000)
error: unable to find plugin 'redpoint-namespace-warnings'
dll unloaded!
```
I believe this is because `LLVM_INSTANTIATE_REGISTRY(FrontendPluginRegistry)` is in `clangFrontend.lib`, and then:
- `clang.exe` gets a copy of it when it's compiled.
- `streamchecker.dll` gets a copy of it when it's compiled.
The option `BUILD_SHARED_LIBS` isn't available on Windows, which would presumably otherwise produce `clangFrontend.dll` which both `clang.exe` and `streamchecker.dll` could share.
I believe there's two ways to fix this:
1. Get `BUILD_SHARED_LIBS` working on Windows so that it produces DLL files, or
2. Pass a function pointer to a known function name (like `CheckerMatcher` or `lldb`), where the provided function calls `add_node` to the real `FrontendPluginRegistry` on the plugin's behalf, e.g.
```cpp
bool success = false;
plugin_info.plugin_init_callback = CastToFPtr<PluginInitCallback>(
plugin_info.library.getAddressOfSymbol("LLDBPluginInitialize"));
if (plugin_info.plugin_init_callback) {
// Call the plug-in "bool LLDBPluginInitialize(void)" function
success = plugin_info.plugin_init_callback();
}
```
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs