cmd/cloner, cmd/viewer: handle named map/slice types with Clone/View methods
The cloner and viewer code generators didn't handle named types
with basic underlying types (map/slice) that have their own Clone
or View methods. For example, a type like:
type Map map[string]any
func (m Map) Clone() Map { ... }
func (m Map) View() MapView { ... }
When used as a struct field, the cloner would descend into the
underlying map[string]any and fail because it can't clone the any
(interface{}) value type. Similarly, the viewer would try to create
a MapFnOf view and fail.
Fix the cloner to check for a Clone method on the named type
before falling through to the underlying type handling.
Fix the viewer to check for a View method on named map/slice types,
so the type author can provide a purpose-built safe view that
doesn't leak raw any values. Named map/slice types without a View
method fall through to normal handling, which correctly rejects
types like map[string]any as unsupported.
Updates tailscale/corp#39502 (needed by tailscale/corp#39594)
Change-Id: Iaef0192a221e02b4b8e409c99ef8398090327744
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
5a899e406d
commit
86f42ea87b
@@ -159,9 +159,26 @@ var _DeeplyNestedMapCloneNeedsRegeneration = DeeplyNestedMap(struct {
|
||||
FourLevels map[string]map[string]map[string]map[string]*SliceContainer
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of NamedMapContainer.
|
||||
// The result aliases no memory with the original.
|
||||
func (src *NamedMapContainer) Clone() *NamedMapContainer {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
dst := new(NamedMapContainer)
|
||||
*dst = *src
|
||||
dst.Attrs = src.Attrs.Clone()
|
||||
return dst
|
||||
}
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _NamedMapContainerCloneNeedsRegeneration = NamedMapContainer(struct {
|
||||
Attrs NamedMap
|
||||
}{})
|
||||
|
||||
// Clone duplicates src into dst and reports whether it succeeded.
|
||||
// To succeed, <src, dst> must be of types <*T, *T> or <*T, **T>,
|
||||
// where T is one of SliceContainer,InterfaceContainer,MapWithPointers,DeeplyNestedMap.
|
||||
// where T is one of SliceContainer,InterfaceContainer,MapWithPointers,DeeplyNestedMap,NamedMapContainer.
|
||||
func Clone(dst, src any) bool {
|
||||
switch src := src.(type) {
|
||||
case *SliceContainer:
|
||||
@@ -200,6 +217,15 @@ func Clone(dst, src any) bool {
|
||||
*dst = src.Clone()
|
||||
return true
|
||||
}
|
||||
case *NamedMapContainer:
|
||||
switch dst := dst.(type) {
|
||||
case *NamedMapContainer:
|
||||
*dst = *src.Clone()
|
||||
return true
|
||||
case **NamedMapContainer:
|
||||
*dst = src.Clone()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user