使用 LoadLibraryA(path_to_dll) 加载 DLL 会将文件描述符 0、1 和 2 的继承句柄标志 (HANDLE_FLAG_INHERIT) 从 1 更改为 0
Loading a DLL with LoadLibraryA(path_to_dll) is changing the inherit handle flag (HANDLE_FLAG_INHERIT) from 1 to 0 for file descriptors 0, 1, and 2
我们已经用 golang 编写了一些函数,并在其之上编写了一个 c 包装器来调用这些函数。我们首先构建 golang 代码以创建存档文件,然后我们在 c 中构建包装器代码以作为 DLL 使用。
在我的程序中使用 LoadLibraryA(path_to_dll) 加载此 DLL 后,我看到 fd 0、1 和 2 的继承标志从 1 更改为 0。这不会在之后立即发生虽然加载 DLL。我在加载库调用后在我的代码中添加了睡眠,似乎在加载库后需要几毫秒才能更改标志值。
我正在使用 GetHandleInformation((HANDLE) sock, &flags) 获取继承标志值。
任何 idea/pointers 可能导致此问题的原因?谢谢!
更新:
我能够在 go 代码中找到翻转继承标志值的确切行。下面 k8sService.go 代码中的全局变量 reqHandler 导致了这一点。 知道为什么使用这个全局变量会翻转继承标志值吗?
my-lib/k8sService.go (go代码)
package main
import "C"
import (
"my-lib/pkg/cmd"
)
func main() {
}
var reqHandler []*cmd.K8sRequest
my-lib/pkg/cmd/execute.go
import (
"my-lib/pkg/dto"
)
type K8sRequest struct {
K8sDetails dto.K8sDetails
}
my-lib/pkg/dto/structs.go
package dto
// K8sDetails contains all the necessary information about talking to the cluster. Below struct has few more variables.
type K8sDetails struct {
// HostName of the cluster's API server
HostName string `json:"hostname"`
// Port on which the API server listens on to
Port int `json:"port"`
}
我们在上面的 k8sService.go 之上有一个 C 包装器。我们首先构建 golang 代码来创建一个存档文件,然后使用这个存档文件和 C 中的包装器代码构建目标 DLL。下面是加载此 DLL 并在加载 DLL 前后打印继承标志值的示例程序。
#include <windows.h>
#include <iostream>
#include <io.h>
#include "wrapper/cWrapper.h"
void printInheritVals() {
typedef SOCKET my_socket_t;
my_socket_t fd0 = _get_osfhandle(0);
my_socket_t fd1 = _get_osfhandle(1);
my_socket_t fd2 = _get_osfhandle(2);
std::cout << "fd0: " << fd0 << std::endl;
std::cout << "fd1: " << fd1 << std::endl;
std::cout << "fd2: " << fd2 << std::endl;
DWORD flags;
int inherit_flag_0 = -1;
int inherit_flag_1 = -1;
int inherit_flag_2 = -1;
if (!GetHandleInformation((HANDLE) fd0, &flags)) {
std::cout << "GetHandleInformation failed" << std::endl;
} else {
inherit_flag_0 = (flags & HANDLE_FLAG_INHERIT);
}
if (!GetHandleInformation((HANDLE) fd1, &flags)) {
std::cout << "GetHandleInformation failed" << std::endl;
} else {
inherit_flag_1 = (flags & HANDLE_FLAG_INHERIT);
}
if (!GetHandleInformation((HANDLE) fd2, &flags)) {
std::cout << "GetHandleInformation failed" << std::endl;
} else {
inherit_flag_2 = (flags & HANDLE_FLAG_INHERIT);
}
std::cout << "inherit_flag_0: " << inherit_flag_0 << std::endl;
std::cout << "inherit_flag_1: " << inherit_flag_1 << std::endl;
std::cout << "inherit_flag_2: " << inherit_flag_2 << std::endl;
}
int main()
{
printInheritVals(); // In output all flag values are 1
HINSTANCE hGetProcIDDLL = LoadLibraryA(PATH_TO_DLL);
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Library loaded" << std::endl;
printInheritVals(); // In output all flag values are 1
Sleep(1000);
printInheritVals(); // In output all flag values are 0
return EXIT_SUCCESS;
}
这是 golang.org/x/sys/windows 包中的错误。同样的问题used to be in the built-in syscall package as well, but it was fixed in Go 1.17.
您项目中的某些东西必须导入 golang.org/x 版本的包而不是 built-in 版本,因此执行以下代码来初始化 Stdin
,Stdout
和 Stderr
变量:
var (
Stdin = getStdHandle(STD_INPUT_HANDLE)
Stdout = getStdHandle(STD_OUTPUT_HANDLE)
Stderr = getStdHandle(STD_ERROR_HANDLE)
)
func getStdHandle(stdhandle uint32) (fd Handle) {
r, _ := GetStdHandle(stdhandle)
CloseOnExec(r)
return r
}
该代码的修复方法是删除 CloseOnExec
调用,这是清除给定文件句柄上的 HANDLE_FLAG_INHERIT
的原因。
如何在您的项目中解决这个问题不太清楚。我想你可以在你的项目中 vendor golang.org/x/sys
模块,或许在你的 go.mod 中使用 replace
指令。在您的本地副本中应用修复程序。
同时,我鼓励您也报告该错误。 The documentation instructs you to report the issue on the main Go project at GitHub,在标题前加上 x/sys.
我们已经用 golang 编写了一些函数,并在其之上编写了一个 c 包装器来调用这些函数。我们首先构建 golang 代码以创建存档文件,然后我们在 c 中构建包装器代码以作为 DLL 使用。
在我的程序中使用 LoadLibraryA(path_to_dll) 加载此 DLL 后,我看到 fd 0、1 和 2 的继承标志从 1 更改为 0。这不会在之后立即发生虽然加载 DLL。我在加载库调用后在我的代码中添加了睡眠,似乎在加载库后需要几毫秒才能更改标志值。
我正在使用 GetHandleInformation((HANDLE) sock, &flags) 获取继承标志值。
任何 idea/pointers 可能导致此问题的原因?谢谢!
更新: 我能够在 go 代码中找到翻转继承标志值的确切行。下面 k8sService.go 代码中的全局变量 reqHandler 导致了这一点。 知道为什么使用这个全局变量会翻转继承标志值吗?
my-lib/k8sService.go (go代码)
package main
import "C"
import (
"my-lib/pkg/cmd"
)
func main() {
}
var reqHandler []*cmd.K8sRequest
my-lib/pkg/cmd/execute.go
import (
"my-lib/pkg/dto"
)
type K8sRequest struct {
K8sDetails dto.K8sDetails
}
my-lib/pkg/dto/structs.go
package dto
// K8sDetails contains all the necessary information about talking to the cluster. Below struct has few more variables.
type K8sDetails struct {
// HostName of the cluster's API server
HostName string `json:"hostname"`
// Port on which the API server listens on to
Port int `json:"port"`
}
我们在上面的 k8sService.go 之上有一个 C 包装器。我们首先构建 golang 代码来创建一个存档文件,然后使用这个存档文件和 C 中的包装器代码构建目标 DLL。下面是加载此 DLL 并在加载 DLL 前后打印继承标志值的示例程序。
#include <windows.h>
#include <iostream>
#include <io.h>
#include "wrapper/cWrapper.h"
void printInheritVals() {
typedef SOCKET my_socket_t;
my_socket_t fd0 = _get_osfhandle(0);
my_socket_t fd1 = _get_osfhandle(1);
my_socket_t fd2 = _get_osfhandle(2);
std::cout << "fd0: " << fd0 << std::endl;
std::cout << "fd1: " << fd1 << std::endl;
std::cout << "fd2: " << fd2 << std::endl;
DWORD flags;
int inherit_flag_0 = -1;
int inherit_flag_1 = -1;
int inherit_flag_2 = -1;
if (!GetHandleInformation((HANDLE) fd0, &flags)) {
std::cout << "GetHandleInformation failed" << std::endl;
} else {
inherit_flag_0 = (flags & HANDLE_FLAG_INHERIT);
}
if (!GetHandleInformation((HANDLE) fd1, &flags)) {
std::cout << "GetHandleInformation failed" << std::endl;
} else {
inherit_flag_1 = (flags & HANDLE_FLAG_INHERIT);
}
if (!GetHandleInformation((HANDLE) fd2, &flags)) {
std::cout << "GetHandleInformation failed" << std::endl;
} else {
inherit_flag_2 = (flags & HANDLE_FLAG_INHERIT);
}
std::cout << "inherit_flag_0: " << inherit_flag_0 << std::endl;
std::cout << "inherit_flag_1: " << inherit_flag_1 << std::endl;
std::cout << "inherit_flag_2: " << inherit_flag_2 << std::endl;
}
int main()
{
printInheritVals(); // In output all flag values are 1
HINSTANCE hGetProcIDDLL = LoadLibraryA(PATH_TO_DLL);
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Library loaded" << std::endl;
printInheritVals(); // In output all flag values are 1
Sleep(1000);
printInheritVals(); // In output all flag values are 0
return EXIT_SUCCESS;
}
这是 golang.org/x/sys/windows 包中的错误。同样的问题used to be in the built-in syscall package as well, but it was fixed in Go 1.17.
您项目中的某些东西必须导入 golang.org/x 版本的包而不是 built-in 版本,因此执行以下代码来初始化 Stdin
,Stdout
和 Stderr
变量:
var (
Stdin = getStdHandle(STD_INPUT_HANDLE)
Stdout = getStdHandle(STD_OUTPUT_HANDLE)
Stderr = getStdHandle(STD_ERROR_HANDLE)
)
func getStdHandle(stdhandle uint32) (fd Handle) {
r, _ := GetStdHandle(stdhandle)
CloseOnExec(r)
return r
}
该代码的修复方法是删除 CloseOnExec
调用,这是清除给定文件句柄上的 HANDLE_FLAG_INHERIT
的原因。
如何在您的项目中解决这个问题不太清楚。我想你可以在你的项目中 vendor golang.org/x/sys
模块,或许在你的 go.mod 中使用 replace
指令。在您的本地副本中应用修复程序。
同时,我鼓励您也报告该错误。 The documentation instructs you to report the issue on the main Go project at GitHub,在标题前加上 x/sys.