克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

go-forceexport

go-forceexport is a golang package that allows access to any module-level function, even ones that are not exported. You give it the string name of a function , like "time.now", and gives you a function value that calls that function. More generally, it can be used to achieve something like reflection on top-level functions, whereas the reflect package only lets you access methods by name.

As you might expect, this library is unsafe and fragile and probably shouldn't be used in production. See "Use cases and pitfalls" below.

It has only been tested on darwin/linux amd64 with Go 1.14. If you find that it works or breaks on other platforms, feel free to submit a pull request with a fix and/or an update to this paragraph.

Installation

$ go get github.com/henrylee2cn/go-forceexport

Usage

Here's how you can grab the time.now function, defined as func now() (sec int64, nsec int32)

var timeNow func() (int64, int32)
err := forceexport.GetFunc(&timeNow, "time.now")
if err != nil {
    // Handle errors if you care about name possibly being invalid.
}
// Calls the actual time.now function.
sec, nsec := timeNow()

The string you give should be the fully-qualified name. For example, here's GetFunc getting itself.

var getFunc func(interface{}, string) error
GetFunc(&getFunc, "github.com/henrylee2cn/go-forceexport.GetFunc")

Use cases and pitfalls

This library is most useful for development and hack projects. For example, you might use it to track down why the standard library isn't behaving as you expect, or you might use it to try out a standard library function to see if it works, then later factor the code to be less fragile. You could also try using it in production; just make sure you're aware of the risks.

There are lots of things to watch out for and ways to shoot yourself in the foot:

  • If you define the wrong function type, you'll get a function with undefined behavior that will likely cause a runtime panic. The library makes no attempt to warn you in this case.
  • Calling unexported functions is inherently fragile because the function won't have any stability guarantees.
  • The implementation relies on the details of internal Go data structures, so later versions of Go might break this library.
  • Since the compiler doesn't expect unexported symbols to be used, it might not create them at all, for example due to inlining or dead code analysis. This means that functions may not show up like you expect, and new versions of the compiler may cause functions to suddenly disappear.
  • If the function you want to use relies on unexported types, you won't be able to trivially use it. However, you can sometimes work around this by defining equivalent copies of those types that you can use, but that approach has its own set of dangers.

How it works

The code is pretty short, so you could just read it, but here's a friendlier explanation:

The code uses the go:linkname compiler directive to get the runtime.activeModules symbol, which is an internal function created by the linker that's used by functions like runtime.FuncForPC. (Using go:linkname is an alternate way to access unexported functions/values, but it has other gotchas and can't be used dynamically.)

Similar to the implementation of runtime.FuncForPC, the code walks the function definitions until it finds one with a matching name, then gets its code pointer.

From there, it creates a function object from the code pointer by calling reflect.MakeFunc and using unsafe.Pointer to swap out the function object's code pointer with the desired one.

Needless to say, it's a scary hack, but it seems to work!

NOTE:

  • For internal functions, if you can't get them, you can try to comment //go:noinline on the function
  • Ensure that the target function is active, that is, ensure that it has been called

License

MIT

The MIT License (MIT) Copyright (c) 2016 Alan Pierce Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

A golang package that allows you to access unexported functions from other packages 展开 收起
Go
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化