-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
Tendermint version (use tendermint version or git rev-parse --verify HEAD if installed from source):
Version 170cb70
What happened:
Auditing dependencies for the cosmos-sdk and I noticed this code
tendermint/libs/bits/bit_array.go
Lines 434 to 444 in 4827ed1
| func (bA *BitArray) FromProto(protoBitArray *tmprotobits.BitArray) { | |
| if protoBitArray == nil { | |
| bA = nil | |
| return | |
| } | |
| bA.Bits = int(protoBitArray.Bits) | |
| if len(protoBitArray.Elems) > 0 { | |
| bA.Elems = protoBitArray.Elems | |
| } | |
| } |
Problems in it:
a) If protoBitArray is nil, it tries to set the pointer receiver to nil; but that operation doesn't reflect on the outside, because of the way pointer receivers are created demoed at https://play.golang.org/p/6IXb-hsVJ7s or inlined below
package main
import "fmt"
func main() {
s := &sk{dt: []int{12, 19}}
s.fromOther(nil)
fmt.Printf("%#v\n", s)
}
type sk struct {
dt []int
}
func (s *sk) fromOther(dk *sk) {
if dk == nil {
s = nil
return
}
s.dt = dk.dt
}it'll still print the prior result
&main.sk{dt:[]int{12, 19}}Did we mean to instead clear out all the fields of the receiver?
It doesn't work because to change a pointer value, you need an lvalue aka a variable receiving it. If it were a **, then one could do *s = nil.
b) FromBitArray blindly reuses the slice passed in from its arguments; which means that someone can later change the underlying slice and mutate the end result
c) ToProto also blindly passes in the underlying slice
tendermint/libs/bits/bit_array.go
Lines 427 to 430 in 4827ed1
| return &tmprotobits.BitArray{ | |
| Bits: int64(bA.Bits), | |
| Elems: bA.Elems, | |
| } |
For both b) and c) we should make a copy of the slice Elems.