Commit bc8bc372 authored by Muhammed Uluyol's avatar Muhammed Uluyol

Properly handle nil interfaces in DeepCopy.

Running reflect.ValueOf(X) where X is a nil interface will return a zero Value. We cannot get the type (because no concrete type is known) and cannot check if the Value is nil later on due to the way reflect.Value works. So we should handle this case by immediately returning nil. We cannot type-assert a nil interface to another interface type (as no concrete type is assigned), so we must add another check to see if the returned interface is nil.
parent 103a39c6
...@@ -736,6 +736,8 @@ func deepCopy_api_List(in List, out *List, c *conversion.Cloner) error { ...@@ -736,6 +736,8 @@ func deepCopy_api_List(in List, out *List, c *conversion.Cloner) error {
for i := range in.Items { for i := range in.Items {
if newVal, err := c.DeepCopy(in.Items[i]); err != nil { if newVal, err := c.DeepCopy(in.Items[i]); err != nil {
return err return err
} else if newVal == nil {
out.Items[i] = nil
} else { } else {
out.Items[i] = newVal.(runtime.Object) out.Items[i] = newVal.(runtime.Object)
} }
...@@ -758,11 +760,15 @@ func deepCopy_api_ListOptions(in ListOptions, out *ListOptions, c *conversion.Cl ...@@ -758,11 +760,15 @@ func deepCopy_api_ListOptions(in ListOptions, out *ListOptions, c *conversion.Cl
} }
if newVal, err := c.DeepCopy(in.LabelSelector); err != nil { if newVal, err := c.DeepCopy(in.LabelSelector); err != nil {
return err return err
} else if newVal == nil {
out.LabelSelector = nil
} else { } else {
out.LabelSelector = newVal.(labels.Selector) out.LabelSelector = newVal.(labels.Selector)
} }
if newVal, err := c.DeepCopy(in.FieldSelector); err != nil { if newVal, err := c.DeepCopy(in.FieldSelector); err != nil {
return err return err
} else if newVal == nil {
out.FieldSelector = nil
} else { } else {
out.FieldSelector = newVal.(fields.Selector) out.FieldSelector = newVal.(fields.Selector)
} }
...@@ -2124,6 +2130,8 @@ func deepCopy_resource_Quantity(in resource.Quantity, out *resource.Quantity, c ...@@ -2124,6 +2130,8 @@ func deepCopy_resource_Quantity(in resource.Quantity, out *resource.Quantity, c
if in.Amount != nil { if in.Amount != nil {
if newVal, err := c.DeepCopy(in.Amount); err != nil { if newVal, err := c.DeepCopy(in.Amount); err != nil {
return err return err
} else if newVal == nil {
out.Amount = nil
} else { } else {
out.Amount = newVal.(*inf.Dec) out.Amount = newVal.(*inf.Dec)
} }
......
...@@ -31,6 +31,8 @@ func deepCopy_resource_Quantity(in resource.Quantity, out *resource.Quantity, c ...@@ -31,6 +31,8 @@ func deepCopy_resource_Quantity(in resource.Quantity, out *resource.Quantity, c
if in.Amount != nil { if in.Amount != nil {
if newVal, err := c.DeepCopy(in.Amount); err != nil { if newVal, err := c.DeepCopy(in.Amount); err != nil {
return err return err
} else if newVal == nil {
out.Amount = nil
} else { } else {
out.Amount = newVal.(*inf.Dec) out.Amount = newVal.(*inf.Dec)
} }
......
...@@ -117,6 +117,13 @@ func (c *Cloner) RegisterGeneratedDeepCopyFunc(deepCopyFunc interface{}) error { ...@@ -117,6 +117,13 @@ func (c *Cloner) RegisterGeneratedDeepCopyFunc(deepCopyFunc interface{}) error {
// DeepCopy will perform a deep copy of a given object. // DeepCopy will perform a deep copy of a given object.
func (c *Cloner) DeepCopy(in interface{}) (interface{}, error) { func (c *Cloner) DeepCopy(in interface{}) (interface{}, error) {
// Can be invalid if we run DeepCopy(X) where X is a nil interface type.
// For example, we get an invalid value when someone tries to deep-copy
// a nil labels.Selector.
// This does not occur if X is nil and is a pointer to a concrete type.
if in == nil {
return nil, nil
}
inValue := reflect.ValueOf(in) inValue := reflect.ValueOf(in)
outValue, err := c.deepCopy(inValue) outValue, err := c.deepCopy(inValue)
if err != nil { if err != nil {
......
...@@ -420,6 +420,8 @@ func (g *deepCopyGenerator) writeDeepCopyForPtr(b *buffer, inField reflect.Struc ...@@ -420,6 +420,8 @@ func (g *deepCopyGenerator) writeDeepCopyForPtr(b *buffer, inField reflect.Struc
ifStmt := fmt.Sprintf(ifFormat, inField.Name) ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent+1) b.addLine(ifStmt, indent+1)
b.addLine("return err\n", indent+2) b.addLine("return err\n", indent+2)
b.addLine("} else if newVal == nil {\n", indent+1)
b.addLine(fmt.Sprintf("out.%s = nil\n", inField.Name), indent+2)
b.addLine("} else {\n", indent+1) b.addLine("} else {\n", indent+1)
assignFormat := "out.%s = newVal.(%s)\n" assignFormat := "out.%s = newVal.(%s)\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type)) assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type))
...@@ -467,6 +469,8 @@ func (g *deepCopyGenerator) writeDeepCopyForSlice(b *buffer, inField reflect.Str ...@@ -467,6 +469,8 @@ func (g *deepCopyGenerator) writeDeepCopyForSlice(b *buffer, inField reflect.Str
ifStmt := fmt.Sprintf(ifFormat, inField.Name) ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent+2) b.addLine(ifStmt, indent+2)
b.addLine("return err\n", indent+3) b.addLine("return err\n", indent+3)
b.addLine("} else if newVal == nil {\n", indent+2)
b.addLine(fmt.Sprintf("out.%s[i] = nil\n", inField.Name), indent+3)
b.addLine("} else {\n", indent+2) b.addLine("} else {\n", indent+2)
assignFormat := "out.%s[i] = newVal.(%s)\n" assignFormat := "out.%s[i] = newVal.(%s)\n"
assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type.Elem())) assignStmt := fmt.Sprintf(assignFormat, inField.Name, g.typeName(inField.Type.Elem()))
...@@ -508,6 +512,8 @@ func (g *deepCopyGenerator) writeDeepCopyForStruct(b *buffer, inType reflect.Typ ...@@ -508,6 +512,8 @@ func (g *deepCopyGenerator) writeDeepCopyForStruct(b *buffer, inType reflect.Typ
ifStmt := fmt.Sprintf(ifFormat, inField.Name) ifStmt := fmt.Sprintf(ifFormat, inField.Name)
b.addLine(ifStmt, indent) b.addLine(ifStmt, indent)
b.addLine("return err\n", indent+1) b.addLine("return err\n", indent+1)
b.addLine("} else if newVal == nil {\n", indent)
b.addLine(fmt.Sprintf("out.%s = nil\n", inField.Name), indent+1)
b.addLine("} else {\n", indent) b.addLine("} else {\n", indent)
copyFormat := "out.%s = newVal.(%s)\n" copyFormat := "out.%s = newVal.(%s)\n"
copyStmt := fmt.Sprintf(copyFormat, inField.Name, g.typeName(inField.Type)) copyStmt := fmt.Sprintf(copyFormat, inField.Name, g.typeName(inField.Type))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment