snapshot: sagernet/gvisor v0.0.0-20260727.0-sing-box-mod.1 + SPEC 048 guard
Обновление снапшота с v0.0.0-20250811.0 на пин, которого требует sing-box после мержа 235 коммитов (upstream d620bbbf2 "Update gvisor to 20260727.0"). Прежний снапшот был взят 2026-08-04 ровно с той версии, на которой тогда стоял апстрим; разрыв возник 2026-08-05 вместе с его бампом. За год апстрим-gvisor изменил ~14 000 строк в 292 файлах. Значимое для нас — сетевой стек: tcp/connect.go (PMTU-discovery + исправление начального RTT/RTO: раньше задержка ACK внутри стека завышала стартовый таймаут на несколько RTT), tcp/snd.go, tcp/rcv.go, stack/conntrack.go, stack/packet_buffer.go. Всего 30 файлов в TCP и 37 в stack. Баг SPEC 048 апстрим НЕ исправил — проверено по коду новой версии: handleConnecting по-прежнему проверяет состояние endpoint'а, но не ep.h, а performHandshake так же зануляет h и отпускает мьютекс до Close(). Поэтому guard перенесён (12 строк) вместе со своим тестом (45 строк). Red/green проверен на новой базе: без guard'а тест падает с той же nil-паникой, что в полевом крашдампе; с ним зелёный.
This commit is contained in:
parent
ffebe42860
commit
117243aa02
293 changed files with 16413 additions and 2842 deletions
|
|
@ -384,7 +384,7 @@ func (s *addrSet) InsertWithoutMergingUnchecked(gap addrGapIterator, r addrRange
|
|||
if splitMaxGap {
|
||||
gap.node.updateMaxGapLeaf()
|
||||
}
|
||||
return addrIterator{gap.node, gap.index}
|
||||
return addrIterator(gap)
|
||||
}
|
||||
|
||||
// InsertRange inserts the given segment into the set. If the new segment can
|
||||
|
|
@ -512,7 +512,7 @@ func (s *addrSet) Remove(seg addrIterator) addrGapIterator {
|
|||
if addrtrackGaps != 0 {
|
||||
seg.node.updateMaxGapLeaf()
|
||||
}
|
||||
return seg.node.rebalanceAfterRemove(addrGapIterator{seg.node, seg.index})
|
||||
return seg.node.rebalanceAfterRemove(addrGapIterator(seg))
|
||||
}
|
||||
|
||||
// RemoveAll removes all segments from the set. All existing iterators are
|
||||
|
|
@ -597,6 +597,19 @@ func (s *addrSet) RemoveFullRangeWith(r addrRange, f func(seg addrIterator)) add
|
|||
}
|
||||
}
|
||||
|
||||
// MoveFrom moves all segments from s2 to s, replacing all existing segments in
|
||||
// s and leaving s2 empty.
|
||||
func (s *addrSet) MoveFrom(s2 *addrSet) {
|
||||
*s = *s2
|
||||
for _, child := range s.root.children {
|
||||
if child == nil {
|
||||
break
|
||||
}
|
||||
child.parent = &s.root
|
||||
}
|
||||
s2.RemoveAll()
|
||||
}
|
||||
|
||||
// Merge attempts to merge two neighboring segments. If successful, Merge
|
||||
// returns an iterator to the merged segment, and all existing iterators are
|
||||
// invalidated. Otherwise, Merge returns a terminal iterator.
|
||||
|
|
@ -1600,7 +1613,7 @@ func (seg addrIterator) PrevGap() addrGapIterator {
|
|||
if seg.node.hasChildren {
|
||||
return seg.node.children[seg.index].lastSegment().NextGap()
|
||||
}
|
||||
return addrGapIterator{seg.node, seg.index}
|
||||
return addrGapIterator(seg)
|
||||
}
|
||||
|
||||
// NextGap returns the gap immediately after the iterated segment.
|
||||
|
|
@ -1889,26 +1902,26 @@ func (n *addrnode) String() string {
|
|||
func (n *addrnode) writeDebugString(buf *bytes.Buffer, prefix string) {
|
||||
if n.hasChildren != (n.nrSegments > 0 && n.children[0] != nil) {
|
||||
buf.WriteString(prefix)
|
||||
buf.WriteString(fmt.Sprintf("WARNING: inconsistent value of hasChildren: got %v, want %v\n", n.hasChildren, !n.hasChildren))
|
||||
fmt.Fprintf(buf, "WARNING: inconsistent value of hasChildren: got %v, want %v\n", n.hasChildren, !n.hasChildren)
|
||||
}
|
||||
for i := 0; i < n.nrSegments; i++ {
|
||||
if child := n.children[i]; child != nil {
|
||||
cprefix := fmt.Sprintf("%s- % 3d ", prefix, i)
|
||||
if child.parent != n || child.parentIndex != i {
|
||||
buf.WriteString(cprefix)
|
||||
buf.WriteString(fmt.Sprintf("WARNING: inconsistent linkage to parent: got (%p, %d), want (%p, %d)\n", child.parent, child.parentIndex, n, i))
|
||||
fmt.Fprintf(buf, "WARNING: inconsistent linkage to parent: got (%p, %d), want (%p, %d)\n", child.parent, child.parentIndex, n, i)
|
||||
}
|
||||
child.writeDebugString(buf, fmt.Sprintf("%s- % 3d ", prefix, i))
|
||||
}
|
||||
buf.WriteString(prefix)
|
||||
if n.hasChildren {
|
||||
if addrtrackGaps != 0 {
|
||||
buf.WriteString(fmt.Sprintf("- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get()))
|
||||
fmt.Fprintf(buf, "- % 3d: %v => %v, maxGap: %d\n", i, n.keys[i], n.values[i], n.maxGap.Get())
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
|
||||
fmt.Fprintf(buf, "- % 3d: %v => %v\n", i, n.keys[i], n.values[i])
|
||||
}
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("- % 3d: %v => %v\n", i, n.keys[i], n.values[i]))
|
||||
fmt.Fprintf(buf, "- % 3d: %v => %v\n", i, n.keys[i], n.values[i])
|
||||
}
|
||||
}
|
||||
if child := n.children[n.nrSegments]; child != nil {
|
||||
|
|
|
|||
|
|
@ -694,6 +694,7 @@ func (ds *decodeState) Load(obj reflect.Value) {
|
|||
// iterations required to finish all objects.
|
||||
if err := safely(func() {
|
||||
for elem := ds.leaves.Front(); elem != nil; elem = elem.Next() {
|
||||
ods = elem.ods
|
||||
ds.checkComplete(elem.ods)
|
||||
}
|
||||
}); err != nil {
|
||||
|
|
@ -714,7 +715,7 @@ func (ds *decodeState) Load(obj reflect.Value) {
|
|||
fmt.Fprintf(&buf, "%q", cycleOS.obj.Type())
|
||||
}
|
||||
buf.WriteString("}")
|
||||
Failf("incomplete graph: %s", string(buf.Bytes()))
|
||||
Failf("incomplete graph: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -770,8 +770,11 @@ func (es *encodeState) Save(obj reflect.Value) {
|
|||
es.encodeObject(oes.obj, oes.how, &oes.encoded)
|
||||
}
|
||||
}); err != nil {
|
||||
// Include the object in the error message.
|
||||
Failf("encoding error: %w\nfor object %#v", err, oes.obj.Interface())
|
||||
// Include the object in the error message, if available.
|
||||
if oes != nil && oes.obj.IsValid() {
|
||||
Failf("encoding error: %w\nfor object %#v", err, oes.obj.Interface())
|
||||
}
|
||||
Failf("encoding error: %w", err)
|
||||
}
|
||||
|
||||
// Check that we have objects to serialize.
|
||||
|
|
@ -802,14 +805,19 @@ func (es *encodeState) Save(obj reflect.Value) {
|
|||
})
|
||||
for _, id := range ids {
|
||||
// Encode the id.
|
||||
oes = nil
|
||||
wire.Save(&es.w, wire.Uint(id))
|
||||
// Marshal the object.
|
||||
oes := es.pending[id]
|
||||
oes = es.pending[id]
|
||||
wire.Save(&es.w, oes.encoded)
|
||||
}
|
||||
}); err != nil {
|
||||
// Include the object and the error.
|
||||
Failf("error serializing object %#v: %w", oes.encoded, err)
|
||||
if oes != nil {
|
||||
// Include the object and the error.
|
||||
Failf("error serializing object %#v: %w", oes.encoded, err)
|
||||
} else {
|
||||
Failf("error serializing type or ID: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func (p *printer) formatRef(x *wire.Ref, graph uint64) string {
|
|||
buf.WriteString(".")
|
||||
buf.WriteString(string(*v))
|
||||
case wire.Index:
|
||||
buf.WriteString(fmt.Sprintf("[%d]", v))
|
||||
fmt.Fprintf(&buf, "[%d]", v)
|
||||
default:
|
||||
panic(fmt.Sprintf("unreachable: switch should be exhaustive, unhandled case %v", reflect.TypeOf(component)))
|
||||
}
|
||||
|
|
@ -147,7 +147,7 @@ func (p *printer) format(graph uint64, depth int, encoded wire.Object) (string,
|
|||
return strings.Join(items, tabs), len(zeros) < len(x.Contents)
|
||||
case *wire.Struct:
|
||||
tag := fmt.Sprintf("g%dt%d", graph, x.TypeID)
|
||||
spec, _ := p.typeSpecs[tag]
|
||||
spec := p.typeSpecs[tag]
|
||||
typ, _ := p.formatType(x.TypeID, graph)
|
||||
if x.Fields() == 0 {
|
||||
return fmt.Sprintf("struct[%s]{}", typ), false
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ func (s Sink) Context() context.Context {
|
|||
// Type is an interface that must be implemented by Struct objects. This allows
|
||||
// these objects to be serialized while minimizing runtime reflection required.
|
||||
//
|
||||
// All these methods can be automatically generated by the go_statify tool.
|
||||
// All these methods can be automatically generated by the go_stateify tool.
|
||||
type Type interface {
|
||||
// StateTypeName returns the type's name.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ var ErrMetadataInvalid = fmt.Errorf("metadata invalid, can't start with _")
|
|||
var ErrInvalidFlags = fmt.Errorf("flags set is invalid")
|
||||
|
||||
const (
|
||||
// CompressionKey is the key for the compression level in the metadata.
|
||||
CompressionKey = "compression"
|
||||
// compressionKey is the key for the compression level in the metadata.
|
||||
compressionKey = "compression"
|
||||
)
|
||||
|
||||
// CompressionLevel is the image compression level.
|
||||
|
|
@ -100,7 +100,7 @@ const (
|
|||
// CompressionLevelNone represents the absence of any compression on an image.
|
||||
CompressionLevelNone = CompressionLevel("none")
|
||||
// CompressionLevelDefault represents the default compression level.
|
||||
CompressionLevelDefault = CompressionLevelFlateBestSpeed
|
||||
CompressionLevelDefault = CompressionLevelNone
|
||||
)
|
||||
|
||||
func (c CompressionLevel) String() string {
|
||||
|
|
@ -109,7 +109,7 @@ func (c CompressionLevel) String() string {
|
|||
|
||||
// ToMetadata returns the compression level as a metadata map.
|
||||
func (c CompressionLevel) ToMetadata() map[string]string {
|
||||
return map[string]string{CompressionKey: string(c)}
|
||||
return map[string]string{compressionKey: string(c)}
|
||||
}
|
||||
|
||||
// CompressionLevelFromString parses a string into the CompressionLevel.
|
||||
|
|
@ -127,21 +127,14 @@ func CompressionLevelFromString(val string) (CompressionLevel, error) {
|
|||
}
|
||||
|
||||
// CompressionLevelFromMetadata returns image compression type stored in the metadata.
|
||||
// If the metadata doesn't contain compression information the default behavior
|
||||
// is the "flate-best-speed" state because the default behavior used to be to always
|
||||
// compress. If the parameter is missing it will be set to default.
|
||||
// If the metadata doesn't contain compression information, the default behavior
|
||||
// is "none" (no compression) and it is added to the metadata.
|
||||
func CompressionLevelFromMetadata(metadata map[string]string) (CompressionLevel, error) {
|
||||
compression := CompressionLevelDefault
|
||||
|
||||
if val, ok := metadata[CompressionKey]; ok {
|
||||
var err error
|
||||
if compression, err = CompressionLevelFromString(val); err != nil {
|
||||
return CompressionLevelNone, err
|
||||
}
|
||||
} else {
|
||||
metadata[CompressionKey] = string(compression)
|
||||
if val, ok := metadata[compressionKey]; ok {
|
||||
return CompressionLevelFromString(val)
|
||||
}
|
||||
|
||||
compression := CompressionLevelDefault
|
||||
metadata[compressionKey] = string(compression)
|
||||
return compression, nil
|
||||
}
|
||||
|
||||
|
|
@ -166,8 +159,12 @@ func NewWriter(w io.Writer, key []byte, metadata map[string]string) (io.WriteClo
|
|||
}
|
||||
|
||||
// Create our HMAC function.
|
||||
h := hmac.New(sha256.New, key)
|
||||
mw := io.MultiWriter(w, h)
|
||||
mw := w
|
||||
var h hash.Hash
|
||||
if len(key) > 0 {
|
||||
h = hmac.New(sha256.New, key)
|
||||
mw = io.MultiWriter(w, h)
|
||||
}
|
||||
|
||||
// First, write the header.
|
||||
if _, err := mw.Write(magicHeader); err != nil {
|
||||
|
|
@ -204,12 +201,14 @@ func NewWriter(w io.Writer, key []byte, metadata map[string]string) (io.WriteClo
|
|||
return nil, err
|
||||
}
|
||||
// Write the current hash.
|
||||
cur := h.Sum(nil)
|
||||
for done := 0; done < len(cur); {
|
||||
n, err := mw.Write(cur[done:])
|
||||
done += n
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if h != nil {
|
||||
cur := h.Sum(nil)
|
||||
for done := 0; done < len(cur); {
|
||||
n, err := mw.Write(cur[done:])
|
||||
done += n
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,8 +239,10 @@ func readMetadataLen(r io.Reader) (uint64, error) {
|
|||
|
||||
// metadata validates the magic header and reads out the metadata from a state
|
||||
// data stream.
|
||||
func metadata(r io.Reader, h hash.Hash) (map[string]string, error) {
|
||||
if h != nil {
|
||||
func metadata(r io.Reader, key []byte) (map[string]string, error) {
|
||||
var h hash.Hash
|
||||
if len(key) > 0 {
|
||||
h = hmac.New(sha256.New, key)
|
||||
r = io.TeeReader(r, h)
|
||||
}
|
||||
|
||||
|
|
@ -285,6 +286,9 @@ func metadata(r io.Reader, h hash.Hash) (map[string]string, error) {
|
|||
cur := h.Sum(nil)
|
||||
buf := make([]byte, len(cur))
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
if err == io.EOF {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if !hmac.Equal(cur, buf) {
|
||||
|
|
@ -304,8 +308,7 @@ func metadata(r io.Reader, h hash.Hash) (map[string]string, error) {
|
|||
// NewReader returns a reader for a statefile.
|
||||
func NewReader(r io.ReadCloser, key []byte) (io.ReadCloser, map[string]string, error) {
|
||||
// Read the metadata with the hash.
|
||||
h := hmac.New(sha256.New, key)
|
||||
metadata, err := metadata(r, h)
|
||||
metadata, err := metadata(r, key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
@ -321,11 +324,12 @@ func NewReader(r io.ReadCloser, key []byte) (io.ReadCloser, map[string]string, e
|
|||
// Pick correct reader
|
||||
var cr io.ReadCloser
|
||||
|
||||
if compression == CompressionLevelFlateBestSpeed {
|
||||
switch compression {
|
||||
case CompressionLevelFlateBestSpeed:
|
||||
cr, err = compressio.NewReader(r, key)
|
||||
} else if compression == CompressionLevelNone {
|
||||
case CompressionLevelNone:
|
||||
cr = compressio.NewSimpleReader(r, key)
|
||||
} else {
|
||||
default:
|
||||
// Should never occur, as it has the default path.
|
||||
return nil, nil, fmt.Errorf("metadata contains invalid compression flag value: %v", compression)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ func (s *Stats) String() string {
|
|||
total time.Duration
|
||||
)
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(fmt.Sprintf("% 16s | % 8s | % 16s | %s\n", "total", "count", "per", "type"))
|
||||
fmt.Fprintf(&buf, "% 16s | % 8s | % 16s | %s\n", "total", "count", "per", "type")
|
||||
buf.WriteString("-----------------+----------+------------------+----------------\n")
|
||||
for _, se := range ss {
|
||||
if se.entry.count == 0 {
|
||||
|
|
@ -135,11 +135,11 @@ func (s *Stats) String() string {
|
|||
count += se.entry.count
|
||||
total += se.entry.total
|
||||
per := se.entry.total / time.Duration(se.entry.count)
|
||||
buf.WriteString(fmt.Sprintf("% 16s | %8d | % 16s | %s\n",
|
||||
se.entry.total, se.entry.count, per, se.name))
|
||||
fmt.Fprintf(&buf, "% 16s | %8d | % 16s | %s\n",
|
||||
se.entry.total, se.entry.count, per, se.name)
|
||||
}
|
||||
buf.WriteString("-----------------+----------+------------------+----------------\n")
|
||||
buf.WriteString(fmt.Sprintf("% 16s | % 8d | % 16s | [all]",
|
||||
total, count, total/time.Duration(count)))
|
||||
return string(buf.Bytes())
|
||||
fmt.Fprintf(&buf, "% 16s | % 8d | % 16s | [all]",
|
||||
total, count, total/time.Duration(count))
|
||||
return buf.String()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,23 +295,23 @@ const interfaceType = "interface"
|
|||
var primitiveTypeDatabase = func() map[string]reflect.Type {
|
||||
r := make(map[string]reflect.Type)
|
||||
for _, t := range []reflect.Type{
|
||||
reflect.TypeOf(false),
|
||||
reflect.TypeOf(int(0)),
|
||||
reflect.TypeOf(int8(0)),
|
||||
reflect.TypeOf(int16(0)),
|
||||
reflect.TypeOf(int32(0)),
|
||||
reflect.TypeOf(int64(0)),
|
||||
reflect.TypeOf(uint(0)),
|
||||
reflect.TypeOf(uintptr(0)),
|
||||
reflect.TypeOf(uint8(0)),
|
||||
reflect.TypeOf(uint16(0)),
|
||||
reflect.TypeOf(uint32(0)),
|
||||
reflect.TypeOf(uint64(0)),
|
||||
reflect.TypeOf(""),
|
||||
reflect.TypeOf(float32(0.0)),
|
||||
reflect.TypeOf(float64(0.0)),
|
||||
reflect.TypeOf(complex64(0.0)),
|
||||
reflect.TypeOf(complex128(0.0)),
|
||||
reflect.TypeFor[bool](),
|
||||
reflect.TypeFor[int](),
|
||||
reflect.TypeFor[int8](),
|
||||
reflect.TypeFor[int16](),
|
||||
reflect.TypeFor[int32](),
|
||||
reflect.TypeFor[int64](),
|
||||
reflect.TypeFor[uint](),
|
||||
reflect.TypeFor[uintptr](),
|
||||
reflect.TypeFor[uint8](),
|
||||
reflect.TypeFor[uint16](),
|
||||
reflect.TypeFor[uint32](),
|
||||
reflect.TypeFor[uint64](),
|
||||
reflect.TypeFor[string](),
|
||||
reflect.TypeFor[float32](),
|
||||
reflect.TypeFor[float64](),
|
||||
reflect.TypeFor[complex64](),
|
||||
reflect.TypeFor[complex128](),
|
||||
} {
|
||||
r[t.Name()] = t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -509,7 +509,7 @@ func loadMap(r *Reader) Map {
|
|||
func (m *Map) save(w *Writer) {
|
||||
l := Uint(len(m.Keys))
|
||||
if int(l) != len(m.Values) {
|
||||
panic(fmt.Sprintf("mismatched keys (%d) Aand values (%d)", len(m.Keys), len(m.Values)))
|
||||
panic(fmt.Sprintf("mismatched keys (%d) and values (%d)", len(m.Keys), len(m.Values)))
|
||||
}
|
||||
l.save(w)
|
||||
if l == 0 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue