【问题标题】:CGO known implementation bug in pointer checks指针检查中的 CGO 已知实现错误
【发布时间】:2021-09-22 10:48:46
【问题描述】:

根据CGO(https://pkg.go.dev/cmd/cgo)的文档,在实现中有一个已知的bug:

注意:当前的实现有一个错误。虽然允许 Go 代码将 nil 或 C 指针(但不是 Go 指针)写入 C 内存,但如果 C 内存的内容看起来是 Go 指针,当前实现有时可能会导致运行时错误。因此,如果 Go 代码要在其中存储指针值,请避免将未初始化的 C 内存传递给 Go 代码。在将 C 中的内存传递给 Go 之前将其清零。

我在 GitHub 的问题跟踪器中查找了此内容,但在那里找不到。有人可以详细说明为什么会发生这种情况吗?运行时如何在未初始化的 C 内存中找到 Go 指针?

例如。假设我将一个未初始化的 char 数组从 C 传递给 Go 函数,运行时如何解释此内存中的 Go 指针?

此外,“如果 Go 代码要在其中存储指针值”部分让我感到困惑。为什么以后使用此内存很重要?

【问题讨论】:

  • "...运行时如何解释此内存中的 Go 指针",除非您使用它来存储指针,否则它不会。它回答了你引用的下一句话:“如果 Go 代码要在其中存储指针值,请避免将未初始化的 C 内存传递给 Go 代码”
  • @JimB,我不是母语人士,但对我来说,手册的引用部分似乎没有提到 C 内存块中的 chasing 指针,它更确切地说是存储指针 into ——也就是说,直接存储。所以,一方面,我支持OP的混乱。你怎么看?
  • @kostix:我认为这一切都归结为“如果 Go 代码要在其中存储指针值,请避免将未初始化的 C 内存传递给 Go 代码”,即一个清晰而简单的指示。剩下的只是尝试提供一些背景知识,而不必完全解释垃圾收集器如何扫描指针。
  • 令我困惑的是,这被称为错误。这不是更多的故障安全,它有一个副作用突然出现在毫无戒心的程序员身上吗?
  • 引用给出了关于如何避免问题的简单说明,但该说明似乎与引用的第一句话脱节。开头似乎描述了一个更广泛的问题。我想更详细地描述错误和触发它的条件。这不需要对指针扫描的完整解释。令我感到奇怪的是,一个新的条件,减少了错误的范围,首先出现在“因此”之后。

标签: go cgo


【解决方案1】:

我在 GitHub 的问题跟踪器中查找了此内容,但在那里找不到。

此评论所指的错误是https://golang.org/issue/19928,诚然不容易找到。 ?

有人可以详细说明为什么会发生这种情况吗?运行时如何在未初始化的 C 内存中找到 Go 指针?

在垃圾收集周期的某些部分,收集器打开“write barrier”以写入 Go 堆中的指针,记录先前存储的指针值以确保在 GC 扫描期间不会丢失。

这里的错误是,写屏障有时也会记录先前存储的指针值,用于Go堆之外的指针。如果该值看起来像一个 Go 指针,垃圾收集器可能会尝试递归扫描它,如果它实际上不是一个有效的指针,则可能会崩溃。

例如。假设我将一个未初始化的 char 数组从 C 传递给 Go 函数,运行时如何解释此内存中的 Go 指针?

如果传递给 Go 的未初始化数据的类型不包含任何指针,则不应出现此错误。因此,特别是对于 char 数组,无论哪种方式都应该没问题。

此外,“如果 Go 代码要在其中存储指针值”部分让我感到困惑。为什么以后使用此内存很重要?

编译器在指针类型的存储指令中插入写屏障。如果 Go 程序不存储指针,则编译器不会发出任何写屏障,也不会触发写屏障中的错误。

【讨论】:

    猜你喜欢
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 2017-10-23
    • 1970-01-01
    相关资源
    最近更新 更多