> 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".

This is not true by my understanding of the spec.
https://go.dev/ref/spec#Package_initialization

If f2.go is passed first, then the order of uninitialized variables is D < 
A < B < C.
As D depends on A, so D is not initialized in the first initialization 
cycle.
In the first initialization cycle, A, B, and C and initialized as 3, 4, and 
3.
In the second initialization cycle, D is initialized as 1 and A is changed 
to 1.
So the output should be 1 4 3.

The same output is for the case if f1.go is passed first.

On Thursday, March 24, 2022 at 5:24:09 AM UTC+8 Ian Lance Taylor wrote:

> On Wed, Mar 23, 2022 at 2:01 PM Joao Carlos <joaoper...@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/f37ab0a1-d287-405f-9e2a-514ab6e60acan%40googlegroups.com.

Reply via email to