Skip to content

Commit 7c349da

Browse files
committed
domain: Fix unbounded allocation and validate succinct set
1 parent 667b8e5 commit 7c349da

1 file changed

Lines changed: 42 additions & 55 deletions

File tree

‎common/domain/set.go‎

Lines changed: 42 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package domain
22

33
import (
44
"encoding/binary"
5-
"io"
65
"math/bits"
76

7+
E "github.com/sagernet/sing/common/exceptions"
88
"github.com/sagernet/sing/common/varbin"
99
)
1010

@@ -47,28 +47,31 @@ func newSuccinctSet(keys []string) *succinctSet {
4747
func (ss *succinctSet) keys() []string {
4848
var result []string
4949
var currentKey []byte
50-
var bmIdx, nodeId int
51-
52-
var traverse func(int, int)
53-
traverse = func(nodeId, bmIdx int) {
54-
if getBit(ss.leaves, nodeId) != 0 {
55-
result = append(result, string(currentKey))
56-
}
57-
58-
for ; ; bmIdx++ {
59-
if getBit(ss.labelBitmap, bmIdx) != 0 {
60-
return
50+
type frame struct {
51+
nodeId, bmIdx int
52+
}
53+
if getBit(ss.leaves, 0) != 0 {
54+
result = append(result, "")
55+
}
56+
stack := []frame{{0, 0}}
57+
for len(stack) > 0 {
58+
top := &stack[len(stack)-1]
59+
if getBit(ss.labelBitmap, top.bmIdx) != 0 {
60+
stack = stack[:len(stack)-1]
61+
if len(stack) > 0 {
62+
currentKey = currentKey[:len(currentKey)-1]
63+
stack[len(stack)-1].bmIdx++
6164
}
62-
nextLabel := ss.labels[bmIdx-nodeId]
63-
currentKey = append(currentKey, nextLabel)
64-
nextNodeId := countZeros(ss.labelBitmap, ss.ranks, bmIdx+1)
65-
nextBmIdx := selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nextNodeId-1) + 1
66-
traverse(nextNodeId, nextBmIdx)
67-
currentKey = currentKey[:len(currentKey)-1]
65+
continue
6866
}
67+
currentKey = append(currentKey, ss.labels[top.bmIdx-top.nodeId])
68+
nextNodeId := countZeros(ss.labelBitmap, ss.ranks, top.bmIdx+1)
69+
nextBmIdx := selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nextNodeId-1) + 1
70+
if getBit(ss.leaves, nextNodeId) != 0 {
71+
result = append(result, string(currentKey))
72+
}
73+
stack = append(stack, frame{nextNodeId, nextBmIdx})
6974
}
70-
71-
traverse(nodeId, bmIdx)
7275
return result
7376
}
7477

@@ -77,18 +80,34 @@ func readSuccinctSet(reader varbin.Reader) (*succinctSet, error) {
7780
if err != nil {
7881
return nil, err
7982
}
80-
leaves, err := readUint64Slice(reader)
83+
leaves, err := varbin.ReadSlice[uint64](reader, binary.BigEndian)
8184
if err != nil {
8285
return nil, err
8386
}
84-
labelBitmap, err := readUint64Slice(reader)
87+
labelBitmap, err := varbin.ReadSlice[uint64](reader, binary.BigEndian)
8588
if err != nil {
8689
return nil, err
8790
}
88-
labels, err := readByteSlice(reader)
91+
labels, err := varbin.ReadSlice[byte](reader, binary.BigEndian)
8992
if err != nil {
9093
return nil, err
9194
}
95+
onesCount := 0
96+
lastOneIndex := -1
97+
for wordIndex, word := range labelBitmap {
98+
onesCount += bits.OnesCount64(word)
99+
if word != 0 {
100+
lastOneIndex = wordIndex<<6 | (63 - bits.LeadingZeros64(word))
101+
}
102+
}
103+
zerosCount := lastOneIndex + 1 - onesCount
104+
if onesCount != zerosCount+1 || len(labels) != zerosCount {
105+
return nil, E.New("domain: malformed succinct set")
106+
}
107+
leavesWordCount := (onesCount + 63) >> 6
108+
if len(leaves) < leavesWordCount {
109+
leaves = append(leaves, make([]uint64, leavesWordCount-len(leaves))...)
110+
}
92111
set := &succinctSet{
93112
leaves: leaves,
94113
labelBitmap: labelBitmap,
@@ -114,22 +133,6 @@ func (ss *succinctSet) Write(writer varbin.Writer) error {
114133
return writeByteSlice(writer, ss.labels)
115134
}
116135

117-
func readUint64Slice(reader varbin.Reader) ([]uint64, error) {
118-
length, err := binary.ReadUvarint(reader)
119-
if err != nil {
120-
return nil, err
121-
}
122-
if length == 0 {
123-
return nil, nil
124-
}
125-
result := make([]uint64, length)
126-
err = binary.Read(reader, binary.BigEndian, result)
127-
if err != nil {
128-
return nil, err
129-
}
130-
return result, nil
131-
}
132-
133136
func writeUint64Slice(writer varbin.Writer, value []uint64) error {
134137
_, err := varbin.WriteUvarint(writer, uint64(len(value)))
135138
if err != nil {
@@ -141,22 +144,6 @@ func writeUint64Slice(writer varbin.Writer, value []uint64) error {
141144
return binary.Write(writer, binary.BigEndian, value)
142145
}
143146

144-
func readByteSlice(reader varbin.Reader) ([]byte, error) {
145-
length, err := binary.ReadUvarint(reader)
146-
if err != nil {
147-
return nil, err
148-
}
149-
if length == 0 {
150-
return nil, nil
151-
}
152-
result := make([]byte, length)
153-
_, err = io.ReadFull(reader, result)
154-
if err != nil {
155-
return nil, err
156-
}
157-
return result, nil
158-
}
159-
160147
func writeByteSlice(writer varbin.Writer, value []byte) error {
161148
_, err := varbin.WriteUvarint(writer, uint64(len(value)))
162149
if err != nil {

0 commit comments

Comments
 (0)