On Wed, Mar 23, 2022 at 2:01 PM Joao Carlos <joaopereira...@gmail.com> wrote:
>
> I'm currently observing a behavior in the package initialization that looks 
> incompatible with the Go language specification.
> Let's consider the following two .go files which are in the same package
>
> f1.go
> package main
>
> var A int = 3
> var B int = A + 1
> var C int = A
>
> f2.go
> package main
>
> import "fmt"
>
> var D = f()
>
> func f() int {
>   A = 1
>   return 1
> }
>
> func main() {
>   fmt.Println(A, " ", B, " ", C)
> }
>
> According to the Go language specification, "package-level variable 
> initialization proceeds stepwise, with each step selecting the variable 
> earliest in declaration order which has no dependencies on uninitialized 
> variables".
>
> As such, I would expect two possible orders in which the global variables can 
> be initialized:
> 1. A < B < C < D - happens when you compile the project by passing f1.go 
> first to the compiler, followed by f2.go . In this case, the output is "1 4 3"
> 2. A < D < B < C - happens when f2.go is passed first to the compiler. In 
> this case, the expected output would be "1 2 1". However, the actual output 
> is "1 2 3".
>
> Adding to this, I observed that if we rewrite f1.go to the following, the 
> program now has the expected behavior when we pass f2.go first to the 
> compiler.
>
> rewritten f1.go
> package main
>
> import "fmt"
>
> var A int = initA()
> var B int = initB()
> var C int = initC()
>
> func initA() int {
>   fmt.Println("Init A")
>   return 3
> }
>
> func initB() int {
>   fmt.Println("Init B")
>   return A + 1
> }
>
> func initC() int {
>   fmt.Println("Init C")
>   return A
> }
>
> Output
> Init A
> Init B
> Init C
> 1   2   1
>
> I observed this behavior in multiple versions of Go, including:
> - go1.16.4 darwin/amd64
> - go1.17.2 linux/amd64
> - go1.18 linux/amd64
>
> Is this the expected behavior? Am I overlooking any details in the Go 
> language specification or in the Go memory model? Or is this a bug in the 
> compiler?

I think you're right: I think this is a bug.

Interestingly, I think the runtime package may rely on this bug.  In
the runtime package I see

var maxSearchAddr = maxOffAddr
var maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset)
& uintptrMask}

and pageAlloc.Init, which is called by mheap.init which is called by
mallocinit which is called by schedinit before package initializers
are run.  So the compiler is implementing an optimization to
initialize maxSearchAddr before running package initialization
routines, which I suppose is OK provided it that it can prove that the
variable is never set by any function run during package
initialization.

Want to open a bug report at https://go.dev/issue?  Thanks.

Ian

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAOyqgcXOAsQFxopNMoLRBaP4aaUD5CXA0m95FW_2zrUpJOR%2Buw%40mail.gmail.com.

Reply via email to