A bug in Go plugin

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

The plugin package is added to Go 1.8, but only the Linux operating system is supported, and there are some known bugs. It can be said that the implementation of this plug-in system has not reached the "product-level" level.

The plugin are currently incomplete, only supports Linux, and have known bugs.

Some known bugs have been pushed to Go1.10 even later in the release.

Today, when testing the functions in Go 1.9, I encountered a bug in plugin.

According to the official documentation, developing a plugin is simple:

Plugin1/main.go
1234567
 Package mainimport"FMT"varintfunc F () {fmt. Printf ("Hello, Number%d\n", V)}

Variables and methods are defined in the plug-in V F , and a file can be generated using the following command so :

1
Go build-buildmode=plugin-o. /p1.so Main.go

The plugin plugin can then be loaded via the package:

main.go
 1234567891011121314 
 p, err: = plugin. Open ( "p1.so" ) if  err! = nil  {panic  (Err)}v, err: = P.lookup () if  err! = nil  {panic  (Err) }f, err: = P.lookup () if  err! =  Nil  {panic  (Err)}*v. (*int ) =  7  F. (func  ()) () //prints "Hello, Number 7 " 

Of course, as a plug-in system, we want to be able to load a new plug-in to replace the existing plug-in, if you copy p1.so as p2.so , and then load the above test code p2.so will be error:

main.go
123456789101112
P, err: = plugin. Open ("p1.so")ifnil {panic(Err)}......p, err = plugin. Open ("p2.so")ifnil {panic(ERR)}

The error message is as follows:

12345
go run main. Go Hello, number 7plugin:plugin plugin/unnamed-f0c47a2a99a0d8e8fb40defabb50f238c78f5d58 already loadedfatal Error:plugin:plugin already loaded ...

This step we can also understand that the same plugin even if the file name changes, loaded into the same, so will report plugin already loaded errors.

Let plugin1/main.go 's change the code in a little bit :

Plugin1/main.go
1234567
 Package mainimport"FMT"varintfunc F () {fmt. Printf ("Hello World,  %d\n", V)}

Then build the plugin p2.so :

1
Go build-buildmode=plugin-o. /p2.so Main.go

Supposedly this time we changed the code, generated a new plug-in, if the code load both plug-ins at the same time, because there is no problem, but run the above load two plug-in test code, found error:

12345
Run  Number 7 error: Plugin:plugin already loaded ...

Weird bar, two different code generation plugin, incredibly is considered to be the same plug-in (plugin/unnamed-f0c47a2a99a0d8e8fb40defabb50f238c78f5d58).

Use nm the symbol table to view two plugins:

123456789101112131415161718192021
[Root@colobu T]# nm p1.so |grep unname00000000001ACFC0 R go.link.pkghashbytes.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d5800000000003f9620 D go.link.pkghash.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d580000000000199080T local.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58. F0000000000199130T local.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58.init0000000000199080T plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58. F0000000000199130T plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58.init000000000048e027 B plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58.initdone000000000048e088 B plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58. V[root@colobu T]#[Root@colobu T]#[Root@colobu T]# nm p2.so |grep unname00000000001ACFC0 R go.link.pkghashbytes.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d5800000000003f9620 D go.link.pkghash.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d580000000000199080T local.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58. F0000000000199130T local.plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58.init0000000000199080T plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58. F0000000000199130T plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58.init000000000048e027 B plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58.initdone000000000048e088 B plugin/unnamed- F0c47a2a99a0d8e8fb40defabb50f238c78f5d58. V[root@colobu T]#

You can see that the symbol table symbol tables generated in the two plugins are the same, so they are mistaken for the same plugin.

This situation is generated in special cases, if the file name of two plug-ins are different, or the reference package is different, or the reference cgo is different, it will generate a different plug-in, loading will not be a problem. However, if the file name is the same and the related references are the same, the same plug-in may be generated, although the plug-in contains different methods and variables, and the implementation is different.

This is when go plugin generated a bug:issue#19358, expect to solve in Go 1.10, the current solution is that the plugin's go file uses a different name, or compile the time specified pluginpath :

12
"-PLUGINPATH=P1" "-pluginpath=p2"-buildmode=plugin-o. /p2.so Main.go

The cause of the problem is as Lionnatsu pointed out in the bug, Go to determine whether the two plug-ins are the same by comparison Pluginpath implementation, if you specify a different when compiling pluginpath , the compiled plug-in is different, but if not specified pluginpath , is generated by an internal algorithm, and the resulting format is plugin/unnamed-" + root.Package.Internal.BuildID .

The Func Computebuildid (P *package) generates a SHA-1 hash value as a buildid.

Go/src/cmd/go/internal/load/pkg.go
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
funcComputebuildid (P *package) {h: = SHA1. New ()//Include The list of files compiled as part of the package.//This lets us detect removed files. See issue 3895.Inputfiles: = str. Stringlist (p.gofiles,p.cgofiles,p.cfiles,p.cxxfiles,p.mfiles,p.hfiles,p.sfiles,p.sysofiles,p.swigfiles,p. Swigcxxfiles,) for_, File: =RangeInputfiles {fmt. fprintf (H,"File%s\n", file)}//Include The content of Runtime/internal/sys/zversion.go in the hash//For the package runtime. This would give package runtime a//different build ID in each Go release.ifP.standard && P.importpath = ="Runtime/internal/sys"&& Cfg.BuildContext.Compiler! ="Gccgo"{data, err: = Ioutil. ReadFile (filepath. Join (P.dir,"Zversion.go"))ifErr! =Nil{base. Fatalf ("Go:%s", err)}fmt. fprintf (H,"Zversion%q\n",string(data))}//Include The build IDs of any dependencies in the hash.//This, combined with the runtime/zversion content,//would cause packages to has different build IDs when//compiled with different Go releases.//This helps the "Go command know to recompile " when//People use the same gopath but switch between//different Go releases. See issue 10702.//This was also a better fix for issue 8290. for_, p1: =Rangep.internal.deps {fmt. fprintf (H,"dep%s%s\n", p1. Importpath, p1. Internal.buildid)}p.internal.buildid = FMT. Sprintf ("%x", H.sum (Nil))}

The latter part of the function generates different hashes for different versions of Go, preventing the user from using different go versions to generate the same ID. Focus on the first half, you can find that the calculation of the hash only depends on the file name, do not care about the contents of the document, which is the same as before we slightly modify the plugin code will generate the same reason, if you in the code will import _ "fmt" also produce a different plug-in.

In short, before go 1.10, in order to avoid plug-ins conflict, it is best to compile the time specified pluginpath , such as:

1
"-pluginpath=plugin/hot-$ (date +%s)" -buildmode=plugin-o hotload.so hotload.go
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.