go.lang.correctness.looppointer.exported_loop_pointer

profile photo of semgrepsemgrep
Author
161
Download Count*

$VALUE is a loop pointer that may be exported from the loop. This pointer is shared between loop iterations, so the exported reference will always point to the last loop value, which is likely unintentional. To fix, copy the pointer to a new pointer within the loop.

Run Locally

Run in CI

Defintion

rules:
  - id: exported_loop_pointer
    message: "`$VALUE` is a loop pointer that may be exported from the loop. This
      pointer is shared between loop iterations, so the exported reference will
      always point to the last loop value, which is likely unintentional. To
      fix, copy the pointer to a new pointer within the loop."
    metadata:
      references:
        - https://github.com/kyoh86/looppointer
      category: correctness
      technology:
        - go
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
    severity: WARNING
    languages:
      - go
    pattern-either:
      - pattern: |
          for _, $VALUE := range $SOURCE {
            <... &($VALUE) ...>
          }
      - pattern: |
          for _, $VALUE := range $SOURCE {
            <... func() { <... &$VALUE ...> } ...>
          }
      - pattern: |
          for _, $VALUE := range $SOURCE {
            <... $ANYTHING(..., <... &$VALUE ...>, ...) ...>
          }

Examples

looppointer.go

func() {
    values := []string{"a", "b", "c"}
    var funcs []func()
    // ruleid:exported_loop_pointer
    for _, val := range values {
        funcs = append(funcs, func() {
            fmt.Println(&val)
        })
    }
}

func() {
    // ruleid:exported_loop_pointer
    for _, val := range values {
        print_pointer(&val)
    }
}


func() {
    values := []string{"a", "b", "c"}
    var funcs []func()
    // ok:exported_loop_pointer
    for _, val := range values {
        val := val // pin!
        funcs = append(funcs, func() {
            fmt.Println(&val)
        })
    }
}

func (){
	input := []string{"a", "b", "c"}
	output := []string{}
    // ok:exported_loop_pointer
	for _, val := range input {
		output = append(output, val)
	}
}