• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

HDT3213 / rdb / 17526273087

07 Sep 2025 08:42AM UTC coverage: 66.434% (-4.6%) from 71.063%
17526273087

push

github

HDT3213
fix intsize calculation error in intset encoding

2 of 2 new or added lines in 1 file covered. (100.0%)

321 existing lines in 3 files now uncovered.

1617 of 2434 relevant lines covered (66.43%)

0.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.7
/core/string.go
1
package core
2

3
import (
4
        "encoding/binary"
5
        "errors"
6
        "fmt"
7
        "math"
8
        "strconv"
9
        "unicode"
10

11
        "github.com/hdt3213/rdb/lzf"
12
)
13

14
const (
15
        len6Bit      = 0
16
        len14Bit     = 1
17
        len32or64Bit = 2
18
        lenSpecial   = 3
19
        len32Bit     = 0x80
20
        len64Bit     = 0x81
21

22
        encodeInt8  = 0
23
        encodeInt16 = 1
24
        encodeInt32 = 2
25
        encodeLZF   = 3
26

27
        maxUint6  = 1<<6 - 1
28
        maxUint14 = 1<<14 - 1
29
        minInt24  = -1 << 23
30
        maxInt24  = 1<<23 - 1
31

32
        len14BitMask      byte = 0b01000000
33
        encodeInt8Prefix       = lenSpecial<<6 | encodeInt8
34
        encodeInt16Prefix      = lenSpecial<<6 | encodeInt16
35
        encodeInt32Prefix      = lenSpecial<<6 | encodeInt32
36
        encodeLZFPrefix        = lenSpecial<<6 | encodeLZF
37
)
38

39
// readLength parse Length Encoding
40
// see: https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format#length-encoding
41
func (dec *Decoder) readLength() (uint64, bool, error) {
1✔
42
        firstByte, err := dec.readByte()
1✔
43
        if err != nil {
1✔
44
                return 0, false, fmt.Errorf("read length failed: %v", err)
×
UNCOV
45
        }
×
46
        lenType := (firstByte & 0xc0) >> 6 // get first 2 bits
1✔
47
        var length uint64
1✔
48
        special := false
1✔
49
        switch lenType {
1✔
50
        case len6Bit:
1✔
51
                length = uint64(firstByte) & 0x3f
1✔
52
        case len14Bit:
1✔
53
                nextByte, err := dec.readByte()
1✔
54
                if err != nil {
1✔
55
                        return 0, false, fmt.Errorf("read len14Bit failed: %v", err)
×
UNCOV
56
                }
×
57
                length = (uint64(firstByte)&0x3f)<<8 | uint64(nextByte)
1✔
58
        case len32or64Bit:
1✔
59
                if firstByte == len32Bit {
2✔
60
                        err = dec.readFull(dec.buffer[0:4])
1✔
61
                        if err != nil {
1✔
62
                                return 0, false, fmt.Errorf("read len32Bit failed: %v", err)
×
UNCOV
63
                        }
×
64
                        length = uint64(binary.BigEndian.Uint32(dec.buffer))
1✔
65
                } else if firstByte == len64Bit {
2✔
66
                        err = dec.readFull(dec.buffer)
1✔
67
                        if err != nil {
1✔
68
                                return 0, false, fmt.Errorf("read len64Bit failed: %v", err)
×
UNCOV
69
                        }
×
70
                        length = binary.BigEndian.Uint64(dec.buffer)
1✔
71
                } else {
×
72
                        return 0, false, fmt.Errorf("illegal length encoding: %x", firstByte)
×
UNCOV
73
                }
×
74
        case lenSpecial:
1✔
75
                special = true
1✔
76
                length = uint64(firstByte) & 0x3f
1✔
77
        }
78
        return length, special, nil
1✔
79
}
80

81
func (dec *Decoder) readString() ([]byte, error) {
1✔
82
        length, special, err := dec.readLength()
1✔
83
        if err != nil {
1✔
84
                return nil, err
×
UNCOV
85
        }
×
86

87
        if special {
2✔
88
                switch length {
1✔
89
                case encodeInt8:
1✔
90
                        b, err := dec.readByte()
1✔
91
                        return []byte(strconv.Itoa(int(int8(b)))), err
1✔
92
                case encodeInt16:
1✔
93
                        b, err := dec.readInt16()
1✔
94
                        return []byte(strconv.Itoa(int(b))), err
1✔
95
                case encodeInt32:
1✔
96
                        b, err := dec.readInt32()
1✔
97
                        return []byte(strconv.Itoa(int(b))), err
1✔
98
                case encodeLZF:
1✔
99
                        return dec.readLZF()
1✔
100
                default:
×
UNCOV
101
                        return []byte{}, errors.New("Unknown string encode type ")
×
102
                }
103
        }
104

105
        res := make([]byte, length)
1✔
106
        err = dec.readFull(res)
1✔
107
        return res, err
1✔
108
}
109

110
func (dec *Decoder) readInt16() (int16, error) {
1✔
111
        err := dec.readFull(dec.buffer[:2])
1✔
112
        if err != nil {
1✔
113
                return 0, fmt.Errorf("read uint16 error: %v", err)
×
UNCOV
114
        }
×
115

116
        i := binary.LittleEndian.Uint16(dec.buffer[:2])
1✔
117
        return int16(i), nil
1✔
118
}
119

120
func (dec *Decoder) readInt32() (int32, error) {
1✔
121
        err := dec.readFull(dec.buffer[:4])
1✔
122
        if err != nil {
1✔
123
                return 0, fmt.Errorf("read uint32 error: %v", err)
×
UNCOV
124
        }
×
125

126
        i := binary.LittleEndian.Uint32(dec.buffer[:4])
1✔
127
        return int32(i), nil
1✔
128
}
129

UNCOV
130
func (dec *Decoder) readInt64() (int64, error) {
×
UNCOV
131
        err := dec.readFull(dec.buffer[:8])
×
132
        if err != nil {
×
133
                return 0, fmt.Errorf("read uint64 error: %v", err)
×
UNCOV
134
        }
×
135

UNCOV
136
        i := binary.LittleEndian.Uint64(dec.buffer[:8])
×
137
        return int64(i), nil
×
138
}
139

140
func (dec *Decoder) readLiteralFloat() (float64, error) {
1✔
141
        first, err := dec.readByte()
1✔
142
        if err != nil {
1✔
UNCOV
143
                return 0, err
×
144
        }
×
145
        if first == 0xff {
1✔
UNCOV
146
                return math.Inf(-1), nil
×
147
        } else if first == 0xfe {
1✔
UNCOV
148
                return math.Inf(1), nil
×
149
        } else if first == 0xfd {
1✔
150
                return math.NaN(), nil
×
UNCOV
151
        }
×
152
        buf := make([]byte, first)
1✔
153
        err = dec.readFull(buf)
1✔
154
        if err != nil {
1✔
UNCOV
155
                return 0, err
×
UNCOV
156
        }
×
157
        str := unsafeBytes2Str(buf)
1✔
158
        val, err := strconv.ParseFloat(str, 64)
1✔
159
        if err != nil {
1✔
UNCOV
160
                return 0, fmt.Errorf("")
×
UNCOV
161
        }
×
162
        return val, err
1✔
163
}
164

165
func (dec *Decoder) readFloat() (float64, error) {
1✔
166
        err := dec.readFull(dec.buffer)
1✔
167
        if err != nil {
1✔
168
                return 0, err
×
UNCOV
169
        }
×
170
        bits := binary.LittleEndian.Uint64(dec.buffer)
1✔
171
        return math.Float64frombits(bits), nil
1✔
172
}
UNCOV
173
func (dec *Decoder) readFloat32() (f float32, err error) {
×
174
        err = dec.readFull(dec.buffer[:4])
×
175
        if err != nil {
×
UNCOV
176
                return 0, err
×
UNCOV
177
        }
×
178
        bits := binary.LittleEndian.Uint32(dec.buffer[:4])
×
179
        return math.Float32frombits(bits), nil
×
180
}
181

182
func (dec *Decoder) readLZF() ([]byte, error) {
1✔
183
        inLen, _, err := dec.readLength()
1✔
184
        if err != nil {
1✔
UNCOV
185
                return nil, err
×
UNCOV
186
        }
×
187
        outLen, _, err := dec.readLength()
1✔
188
        if err != nil {
1✔
UNCOV
189
                return nil, err
×
UNCOV
190
        }
×
191
        val := make([]byte, inLen)
1✔
192
        err = dec.readFull(val)
1✔
193
        if err != nil {
1✔
UNCOV
194
                return nil, err
×
UNCOV
195
        }
×
196
        return lzf.Decompress(val, int(inLen), int(outLen))
1✔
197
}
198

199
func (enc *Encoder) writeLength(value uint64) error {
1✔
200
        var buf []byte
1✔
201
        if value <= maxUint6 {
2✔
202
                // 00 + 6 bits of data
1✔
203
                enc.buffer[0] = byte(value)
1✔
204
                buf = enc.buffer[0:1]
1✔
205
        } else if value <= maxUint14 {
3✔
206
                enc.buffer[0] = byte(value>>8) | len14BitMask // high 6 bit and mask(0x40)
1✔
207
                enc.buffer[1] = byte(value)                   // low 8 bit
1✔
208
                buf = enc.buffer[0:2]
1✔
209
        } else if value <= math.MaxUint32 {
3✔
210
                buf = make([]byte, 5)
1✔
211
                buf[0] = len32Bit
1✔
212
                binary.BigEndian.PutUint32(buf[1:], uint32(value))
1✔
213
        } else {
2✔
214
                buf = make([]byte, 9)
1✔
215
                buf[0] = len64Bit
1✔
216
                binary.BigEndian.PutUint64(buf[1:], value)
1✔
217
        }
1✔
218
        return enc.write(buf)
1✔
219
}
220

221
func (enc *Encoder) writeSimpleString(s string) error {
1✔
222
        err := enc.writeLength(uint64(len(s)))
1✔
223
        if err != nil {
1✔
UNCOV
224
                return err
×
UNCOV
225
        }
×
226
        return enc.write([]byte(s))
1✔
227
}
228

229
func (enc *Encoder) tryWriteIntString(s string) (bool, error) {
1✔
230
        intVal, ok := isEncodableUint32(s)
1✔
231
        if !ok {
2✔
232
                return false, nil
1✔
233
        }
1✔
234
        var err error
1✔
235
        if intVal >= math.MinInt8 && intVal <= math.MaxInt8 {
2✔
236
                err = enc.write([]byte{encodeInt8Prefix, byte(int8(intVal))})
1✔
237
        } else if intVal >= math.MinInt16 && intVal <= math.MaxInt16 {
3✔
238
                buf := enc.buffer[0:3]
1✔
239
                buf[0] = encodeInt16Prefix
1✔
240
                binary.LittleEndian.PutUint16(buf[1:], uint16(int16(intVal)))
1✔
241
                err = enc.write(buf)
1✔
242
        } else if intVal >= math.MinInt32 && intVal <= math.MaxInt32 {
3✔
243
                buf := enc.buffer[0:5]
1✔
244
                buf[0] = encodeInt32Prefix
1✔
245
                binary.LittleEndian.PutUint32(buf[1:], uint32(int32(intVal)))
1✔
246
                err = enc.write(buf)
1✔
247
        } else {
1✔
UNCOV
248
                // beyond int32 range, but within int64 range
×
249
                return false, nil
×
250
        }
×
251
        if err != nil {
1✔
UNCOV
252
                return true, err
×
253
        }
×
254
        return true, nil
1✔
255
}
256

257
func (enc *Encoder) writeLZFString(s string) error {
1✔
258
        out, err := lzf.Compress([]byte(s))
1✔
259
        if err != nil {
1✔
UNCOV
260
                return err
×
UNCOV
261
        }
×
262
        err = enc.write([]byte{encodeLZFPrefix})
1✔
263
        if err != nil {
1✔
264
                return err
×
UNCOV
265
        }
×
266
        // write compressed length
267
        err = enc.writeLength(uint64(len(out)))
1✔
268
        if err != nil {
1✔
UNCOV
269
                return err
×
UNCOV
270
        }
×
271
        // write uncompressed length
272
        err = enc.writeLength(uint64(len(s)))
1✔
273
        if err != nil {
1✔
UNCOV
274
                return err
×
UNCOV
275
        }
×
276
        return enc.write(out)
1✔
277
}
278

279
func (enc *Encoder) writeString(s string) error {
1✔
280
        isInt, err := enc.tryWriteIntString(s)
1✔
281
        if err != nil {
1✔
UNCOV
282
                return err
×
UNCOV
283
        }
×
284
        if isInt {
2✔
285
                return nil
1✔
286
        }
1✔
287
        // Try LZF compression - under 20 bytes it's unable to compress even so skip it
288
        // see rdbSaveRawString at [rdb.c](https://github.com/redis/redis/blob/unstable/src/rdb.c#L449)
289
        if enc.compress && len(s) > 20 {
2✔
290
                err = enc.writeLZFString(s)
1✔
291
                if err == nil { // lzf may failed, while out > in
2✔
292
                        return nil
1✔
293
                }
1✔
294
        }
295
        return enc.writeSimpleString(s)
1✔
296
}
297

298
// write string without try int string. for tryWriteIntSetEncoding, writeZipList
299
func (enc *Encoder) writeNanString(s string) error {
1✔
300
        if enc.compress && len(s) > 20 {
1✔
301
                err := enc.writeLZFString(s)
×
302
                if err == nil { // lzf may failed, while out > in
×
UNCOV
303
                        return nil
×
UNCOV
304
                }
×
305
        }
306
        return enc.writeSimpleString(s)
1✔
307
}
308

309
func (enc *Encoder) WriteStringObject(key string, value []byte, options ...interface{}) error {
1✔
310
        err := enc.beforeWriteObject(options...)
1✔
311
        if err != nil {
1✔
UNCOV
312
                return err
×
313
        }
×
314
        err = enc.write([]byte{typeString})
1✔
315
        if err != nil {
1✔
UNCOV
316
                return err
×
UNCOV
317
        }
×
318
        err = enc.writeString(key)
1✔
319
        if err != nil {
1✔
UNCOV
320
                return err
×
UNCOV
321
        }
×
322
        err = enc.writeString(unsafeBytes2Str(value))
1✔
323
        if err != nil {
1✔
UNCOV
324
                return err
×
UNCOV
325
        }
×
326
        enc.state = writtenObjectState
1✔
327
        return nil
1✔
328
}
329

330
func (enc *Encoder) writeFloat64(f float64) error {
1✔
331
        bin := math.Float64bits(f)
1✔
332
        binary.LittleEndian.PutUint64(enc.buffer, bin)
1✔
333
        return enc.write(enc.buffer)
1✔
334
}
1✔
335

336
// a string might be encoded as an integer, but only subset (aka uint32) of the number set
337
// can be encoded and then decoded back.
338
// e.g. the following strings can not be encoded as an integer:
339
// "007", "-0", "-1", "+0", "+1", "0x11"
340
func isEncodableUint32(s string) (int64, bool) {
1✔
341
        if s == "" {
2✔
342
                return 0, false
1✔
343
        }
1✔
344
        if s[0] == '0' && len(s) > 1 {
2✔
345
                return 0, false
1✔
346
        }
1✔
347
        for _, r := range s {
2✔
348
                if !unicode.IsDigit(r) {
2✔
349
                        return 0, false
1✔
350
                }
1✔
351
        }
352
        intVal, err := strconv.ParseInt(s, 10, 32)
1✔
353
        if err != nil {
2✔
354
                return 0, false
1✔
355
        }
1✔
356
        return intVal, true
1✔
357
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc