[go-marshal] Update API

- All Marshal* and Unmarshal* methods now require buffers to be correctly sized
- Only the Copy{In/Out} variants can handle smaller buffers (or address spaces)

PiperOrigin-RevId: 322953881
This commit is contained in:
Ayush Ranjan 2020-07-24 01:14:32 -07:00 committed by gVisor bot
parent 65b5e64802
commit c59b792f53
3 changed files with 34 additions and 34 deletions

View File

@ -413,13 +413,13 @@ func (g *Generator) Run() error {
for _, t := range g.collectMarshallableTypes(a, fsets[i]) { for _, t := range g.collectMarshallableTypes(a, fsets[i]) {
impl := g.generateOne(t, fsets[i]) impl := g.generateOne(t, fsets[i])
// Collect Marshallable types referenced by the generated code. // Collect Marshallable types referenced by the generated code.
for ref, _ := range impl.ms { for ref := range impl.ms {
ms[ref] = struct{}{} ms[ref] = struct{}{}
} }
impls = append(impls, impl) impls = append(impls, impl)
// Collect imports referenced by the generated code and add them to // Collect imports referenced by the generated code and add them to
// the list of imports we need to copy to the generated code. // the list of imports we need to copy to the generated code.
for name, _ := range impl.is { for name := range impl.is {
if !g.imports.markUsed(name) { if !g.imports.markUsed(name) {
panic(fmt.Sprintf("Generated code for '%s' referenced a non-existent import with local name '%s'. Either go-marshal needs to add an import to the generated file, or a package in an input source file has a package name differ from the final component of its path, which go-marshal doesn't know how to detect; use an import alias to work around this limitation.", impl.typeName(), name)) panic(fmt.Sprintf("Generated code for '%s' referenced a non-existent import with local name '%s'. Either go-marshal needs to add an import to the generated file, or a package in an input source file has a package name differ from the final component of its path, which go-marshal doesn't know how to detect; use an import alias to work around this limitation.", impl.typeName(), name))
} }

View File

@ -268,6 +268,10 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
g.emit("// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.\n") g.emit("// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.\n")
g.emit("func (%s *%s) MarshalUnsafe(dst []byte) {\n", g.r, g.typeName()) g.emit("func (%s *%s) MarshalUnsafe(dst []byte) {\n", g.r, g.typeName())
g.inIndent(func() { g.inIndent(func() {
fallback := func() {
g.emit("// Type %s doesn't have a packed layout in memory, fallback to MarshalBytes.\n", g.typeName())
g.emit("%s.MarshalBytes(dst)\n", g.r)
}
if thisPacked { if thisPacked {
g.recordUsedImport("safecopy") g.recordUsedImport("safecopy")
g.recordUsedImport("unsafe") g.recordUsedImport("unsafe")
@ -277,16 +281,13 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r) g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r)
}) })
g.emit("} else {\n") g.emit("} else {\n")
g.inIndent(func() { g.inIndent(fallback)
g.emit("%s.MarshalBytes(dst)\n", g.r)
})
g.emit("}\n") g.emit("}\n")
} else { } else {
g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r) g.emit("safecopy.CopyIn(dst, unsafe.Pointer(%s))\n", g.r)
} }
} else { } else {
g.emit("// Type %s doesn't have a packed layout in memory, fallback to MarshalBytes.\n", g.typeName()) fallback()
g.emit("%s.MarshalBytes(dst)\n", g.r)
} }
}) })
g.emit("}\n\n") g.emit("}\n\n")
@ -294,6 +295,10 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
g.emit("// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.\n") g.emit("// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.\n")
g.emit("func (%s *%s) UnmarshalUnsafe(src []byte) {\n", g.r, g.typeName()) g.emit("func (%s *%s) UnmarshalUnsafe(src []byte) {\n", g.r, g.typeName())
g.inIndent(func() { g.inIndent(func() {
fallback := func() {
g.emit("// Type %s doesn't have a packed layout in memory, fallback to UnmarshalBytes.\n", g.typeName())
g.emit("%s.UnmarshalBytes(src)\n", g.r)
}
if thisPacked { if thisPacked {
g.recordUsedImport("safecopy") g.recordUsedImport("safecopy")
g.recordUsedImport("unsafe") g.recordUsedImport("unsafe")
@ -303,16 +308,13 @@ func (g *interfaceGenerator) emitMarshallableForStruct(st *ast.StructType) {
g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r) g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r)
}) })
g.emit("} else {\n") g.emit("} else {\n")
g.inIndent(func() { g.inIndent(fallback)
g.emit("%s.UnmarshalBytes(src)\n", g.r)
})
g.emit("}\n") g.emit("}\n")
} else { } else {
g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r) g.emit("safecopy.CopyOut(unsafe.Pointer(%s), src)\n", g.r)
} }
} else { } else {
g.emit("// Type %s doesn't have a packed layout in memory, fall back to UnmarshalBytes.\n", g.typeName()) fallback()
g.emit("%s.UnmarshalBytes(src)\n", g.r)
} }
}) })
g.emit("}\n\n") g.emit("}\n\n")
@ -463,8 +465,10 @@ func (g *interfaceGenerator) emitMarshallableSliceForStruct(st *ast.StructType,
}) })
g.emit("}\n\n") g.emit("}\n\n")
g.emit("// Handle any final partial object.\n") g.emit("// Handle any final partial object. buf is guaranteed to be long enough for the\n")
g.emit("if length < size*count && length%size != 0 {\n") g.emit("// final element, but may not contain valid data for the entire range. This may\n")
g.emit("// result in unmarshalling zero values for some parts of the object.\n")
g.emit("if length%size != 0 {\n")
g.inIndent(func() { g.inIndent(func() {
g.emit("idx := limit\n") g.emit("idx := limit\n")
g.emit("dst[idx].UnmarshalBytes(buf[size*idx:size*(idx+1)])\n") g.emit("dst[idx].UnmarshalBytes(buf[size*idx:size*(idx+1)])\n")

View File

@ -58,18 +58,12 @@ type Marshallable interface {
// likely make use of the type of these fields). // likely make use of the type of these fields).
SizeBytes() int SizeBytes() int
// MarshalBytes serializes a copy of a type to dst. dst may be smaller than // MarshalBytes serializes a copy of a type to dst.
// SizeBytes(), which results in a part of the struct being marshalled. Note // Precondition: dst must be at least SizeBytes() in length.
// that this may have unexpected results for non-packed types, as implicit
// padding needs to be taken into account when reasoning about how much of
// the type is serialized.
MarshalBytes(dst []byte) MarshalBytes(dst []byte)
// UnmarshalBytes deserializes a type from src. src may be smaller than // UnmarshalBytes deserializes a type from src.
// SizeBytes(), which results in a partially deserialized struct. Note that // Precondition: src must be at least SizeBytes() in length.
// this may have unexpected results for non-packed types, as implicit
// padding needs to be taken into account when reasoning about how much of
// the type is deserialized.
UnmarshalBytes(src []byte) UnmarshalBytes(src []byte)
// Packed returns true if the marshalled size of the type is the same as the // Packed returns true if the marshalled size of the type is the same as the
@ -89,8 +83,8 @@ type Marshallable interface {
// representation to the dst buffer. This is only safe to do when the type // representation to the dst buffer. This is only safe to do when the type
// has no implicit padding, see Marshallable.Packed. When Packed would // has no implicit padding, see Marshallable.Packed. When Packed would
// return false, MarshalUnsafe should fall back to the safer but slower // return false, MarshalUnsafe should fall back to the safer but slower
// MarshalBytes. dst may be smaller than SizeBytes(), see comment for // MarshalBytes.
// MarshalBytes for implications. // Precondition: dst must be at least SizeBytes() in length.
MarshalUnsafe(dst []byte) MarshalUnsafe(dst []byte)
// UnmarshalUnsafe deserializes a type by directly copying to the underlying // UnmarshalUnsafe deserializes a type by directly copying to the underlying
@ -99,8 +93,8 @@ type Marshallable interface {
// This allows much faster unmarshalling of types which have no implicit // This allows much faster unmarshalling of types which have no implicit
// padding, see Marshallable.Packed. When Packed would return false, // padding, see Marshallable.Packed. When Packed would return false,
// UnmarshalUnsafe should fall back to the safer but slower unmarshal // UnmarshalUnsafe should fall back to the safer but slower unmarshal
// mechanism implemented in UnmarshalBytes. src may be smaller than // mechanism implemented in UnmarshalBytes.
// SizeBytes(), see comment for UnmarshalBytes for implications. // Precondition: src must be at least SizeBytes() in length.
UnmarshalUnsafe(src []byte) UnmarshalUnsafe(src []byte)
// CopyIn deserializes a Marshallable type from a task's memory. This may // CopyIn deserializes a Marshallable type from a task's memory. This may
@ -149,14 +143,16 @@ type Marshallable interface {
// //
// Generates four additional functions for marshalling slices of Foos like this: // Generates four additional functions for marshalling slices of Foos like this:
// //
// // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It's // // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It
// // more efficient that repeatedly calling calling Foo.MarshalUnsafe over a // // might be more efficient that repeatedly calling Foo.MarshalUnsafe
// // []Foo in a loop. // // over a []Foo in a loop if the type is Packed.
// // Preconditions: dst must be at least len(src)*Foo.SizeBytes() in length.
// func MarshalUnsafeFooSlice(src []Foo, dst []byte) (int, error) { ... } // func MarshalUnsafeFooSlice(src []Foo, dst []byte) (int, error) { ... }
// //
// // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It's // // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It
// // more efficient that repeatedly calling calling Foo.UnmarshalUnsafe over a // // might be more efficient that repeatedly calling Foo.UnmarshalUnsafe
// // []Foo in a loop. // // over a []Foo in a loop if the type is Packed.
// // Preconditions: src must be at least len(dst)*Foo.SizeBytes() in length.
// func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) (int, error) { ... } // func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) (int, error) { ... }
// //
// // CopyFooSliceIn copies in a slice of Foo objects from the task's memory. // // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.