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

Reply via email to