Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access unexported package private variable

Tags:

go

Code like below

package internal

var internalVar = "foobar"

How can i access this internalVar from another package like package main?

internal package is placed in a 3rd party library, and my application needs to use some private info which original author is not willing to expose as a public API.

like image 874
ayanamist Avatar asked Oct 19 '25 18:10

ayanamist


1 Answers

As @mkopriva mentioned, internal variables should not be accessed outside their packages at all. Go explicitly does that as a way to enforce accessibility and if the internal var is not exported, then it shouldn't be accessed. Again: don't do this, it's bad Go and we don't like it. Always export your variables when you need to access them outside your packages.

That huge disclaimer above being said, there are ways on how you can access internal variables: pointers, assembly and linkname. I'll explain the later since it's the easiest one:

Go compiler has this nifty directive called //go:linkname. It basically links variables/functions between different packages. From the documentation:

//go:linkname localname [importpath.name]

This special directive does not apply to the Go code that follows it. Instead, the //go:linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code. If the “importpath.name” argument is omitted, the directive uses the symbol's default object file symbol name and only has the effect of making the symbol accessible to other packages. Because this directive can subvert the type system and package modularity, it is only enabled in files that have imported "unsafe".

That means that you can use it to access otherwise unexported functions and variables, with something like this:

main.go

package main

import (
    "temp/test-access-internal/internal"

    _ "unsafe"
)

//go:linkname message temp/test-access-internal/internal.message
var message string

func main() {
    message = "abc"
    println(message)
    internal.SayHello()
}

internal/internal.go

package internal

var message string = "Hello!"

func SayHello() {
    println(message)
}

You will see that the output respects the "abc" value we've overwritten.

Don't do this unless you really, really needs to monkey patch something.

like image 193
Gustavo Kawamoto Avatar answered Oct 21 '25 11:10

Gustavo Kawamoto



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!