Hello everyone.

I have a question about a common programming error I have made several 
times. It regards the use of a pointer to a loop variable outside of the 
loop. Basically, we want to convert a slice, map, or channel of items (the 
source sequence) into a map, slice, or channel of pointers to respective 
items in the source sequence. But, rather than point to the actual values, 
we point to the loop variable.
I have written some code in a GitHub gist to demonstrate this mistake 
<https://gist.github.com/barisere/408fbfb4a0f024bcafced1bf99544b27>. I 
think this mistake can be caught by code analysis tools, but I don't know 
of any that catches these. If there is any, please let me know so that I 
can save my future self some unnecessary trouble. If there isn't, how can I 
make one (probably add it to vet)?
Here's the code sample, if you prefer to read it all here.


// escape_test.go

package main_test

import (
    "testing"
    "testing/quick"
    "unsafe"
)

func all(xs []*int, f func(x *int) bool) (result bool) {
    result = true
    for _, v := range xs {
        result = result && f(v)
    }
    return result
}

func Test_references_to_loop_variable_outside_the_loop_have_same_value(t 
*testing.T) {
    f := func(xs []int) bool {
        var loopVariableAddress uintptr
        var zeroOfUintptr uintptr
        var copies = make([]*int, 0, len(xs))
        for _, x := range xs {
            if loopVariableAddress == zeroOfUintptr {
                // Store the loop variable's address for later comparison.
                loopVariableAddress = uintptr(unsafe.Pointer(&x))
            }
            // Copy the address of x into a slice.
            copies = append(copies, &x)
            // The append statement above is most likely a mistake.
            // We probably mean
            // copies = append(copies, &xs[index]);
            // assuming `index` is the ignored loop index.
        }
        return all(copies, func(x *int) bool {
            // All values in `copies` are the same pointer address.
            return uintptr(unsafe.Pointer(x)) == loopVariableAddress && *x 
== *copies[0]
        })
    }

    if err := quick.Check(f, nil); err != nil {
        t.Fatal(err)
    }
}

-- 
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/cfbc843b-2acf-4440-81d2-01ab68a6628bn%40googlegroups.com.

Reply via email to