Proposal Details
The proposal is to extend the loopclosure checker to additionally warn with a variables in a 3-clause for loop is written to after Go 1.22. A part of the new semantics is to copy the iterator variable at the end of the for loop. This is a READ that can race with writes from other goroutines.
Example:
for i := 0; i < N; i ++ {
go func() {
i *= 10 // warn "loop variable i written by func literal"
println(i)
}()
}
Criteria to use:
- There is a 3-clause for loop declaring a variable
v.
- It is in a file with GoVersion >= 1.22.
- The 'last' instruction in the loop body is a
go statement.
- The function executed is a function literal.
- The function literal contains an assignment (or IncDecStmt).
- The assignment updates the loop variable according to the following recursive definition in some left hand side:
Updates(id) holds when id refers to the variable,
Updates(e.X) holds when Updates(e),
Updates(e[g]) holds when Updates(e),
Updates(*e) holds when Updates(e),
- and otherwise
Updates(e) does not hold.
Additionally:
- See loopclosure
forEachLastStmt for the operational definition of 'last'.
- In addition to
go statements this would be reported for errgroup.Go and t.Run() when t.Parrallel is present. It will not be reported for defer statements.
To discuss: The requirements give at the moment dereference pointers. This is not sufficient to ensure a race has occurred. Just that a race is overwhelmingly likely. This seems to be in the spirit of the existing loopclosure check. Curious whether others agree or think we should not report if there is indirection.
Proposal Details
The proposal is to extend the
loopclosurechecker to additionally warn with a variables in a 3-clause for loop is written to after Go 1.22. A part of the new semantics is to copy the iterator variable at the end of the for loop. This is a READ that can race with writes from other goroutines.Example:
Criteria to use:
v.gostatement.Updates(id)holds whenidrefers to the variable,Updates(e.X)holds whenUpdates(e),Updates(e[g])holds whenUpdates(e),Updates(*e)holds whenUpdates(e),Updates(e)does not hold.Additionally:
forEachLastStmtfor the operational definition of 'last'.gostatements this would be reported forerrgroup.Goandt.Run()whent.Parrallelis present. It will not be reported fordeferstatements.To discuss: The requirements give at the moment dereference pointers. This is not sufficient to ensure a race has occurred. Just that a race is overwhelmingly likely. This seems to be in the spirit of the existing loopclosure check. Curious whether others agree or think we should not report if there is indirection.