1
0
mirror of https://github.com/golang/go synced 2024-10-01 04:08:32 -06:00

related reflect bug: make copies of big values

so that callers cannot edit large values inside interfaces.

R=r
DELTA=52  (42 added, 1 deleted, 9 changed)
OCL=29180
CL=29195
This commit is contained in:
Russ Cox 2009-05-21 14:06:43 -07:00
parent 8b6b380605
commit f96662324e
2 changed files with 50 additions and 9 deletions

View File

@ -583,3 +583,31 @@ func TestInterfaceExtraction(t *testing.T) {
t.Errorf("Interface() on interface: ", v, s.w); t.Errorf("Interface() on interface: ", v, s.w);
} }
} }
func TestInterfaceEditing(t *testing.T) {
// strings are bigger than one word,
// so the interface conversion allocates
// memory to hold a string and puts that
// pointer in the interface.
var i interface{} = "hello";
// if i pass the interface value by value
// to NewValue, i should get a fresh copy
// of the value.
v := NewValue(i);
// and setting that copy to "bye" should
// not change the value stored in i.
v.(StringValue).Set("bye");
if i.(string) != "hello" {
t.Errorf(`Set("bye") changed i to %s`, i.(string));
}
// the same should be true of smaller items.
i = 123;
v = NewValue(i);
v.(IntValue).Set(234);
if i.(int) != 123 {
t.Errorf("Set(234) changed i to %d", i.(int));
}
}

View File

@ -646,7 +646,6 @@ func (v *arrayValueStruct) Set(src ArrayValue) {
func (v *arrayValueStruct) Elem(i int) Value { func (v *arrayValueStruct) Elem(i int) Value {
data_uint := uintptr(v.addr) + uintptr(i * v.elemsize); data_uint := uintptr(v.addr) + uintptr(i * v.elemsize);
return newValueAddr(v.elemtype, Addr(data_uint)); return newValueAddr(v.elemtype, Addr(data_uint));
return nil
} }
func (v *arrayValueStruct) CopyFrom(src ArrayValue, n int) { func (v *arrayValueStruct) CopyFrom(src ArrayValue, n int) {
@ -949,16 +948,30 @@ func NewValue(e interface {}) Value {
typecache[typestring] = typ; typecache[typestring] = typ;
} }
var ap Addr;
if indir { if indir {
// Content of interface is a pointer. // Content of interface is large and didn't
return newValueAddr(typ, Addr(uintptr(value))); // fit, so it's a pointer to the actual content.
// We have an address, but we need to
// make a copy to avoid letting the caller
// edit the content inside the interface.
n := uintptr(typ.Size());
data := make([]byte, n);
p1 := uintptr(Addr(&data[0]));
p2 := uintptr(value);
for i := uintptr(0); i < n; i++ {
*(*byte)(Addr(p1+i)) = *(*byte)(Addr(p2+i));
} }
ap = Addr(&data[0]);
// Content of interface is a value; } else {
// need a permanent copy to take its address. // Content of interface is small and stored
ap := new(uint64); // inside the interface. Make a copy so we
*ap = value; // can take its address.
return newValueAddr(typ, Addr(ap)); x := new(uint64);
*x = value;
ap = Addr(x);
}
return newValueAddr(typ, ap);
} }
// Indirect indirects one level through a value, if it is a pointer. // Indirect indirects one level through a value, if it is a pointer.