Bug Summary

File:src/listpack.c
Warning:line 756, column 9
Value stored to 'dst' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name listpack.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mthread-model posix -mframe-pointer=none -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -D REDIS_STATIC= -I ../deps/hiredis -I ../deps/linenoise -I ../deps/lua/src -I ../deps/hdr_histogram -D USE_JEMALLOC -I ../deps/jemalloc/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-c11-extensions -Wno-missing-field-initializers -std=c11 -fdebug-compilation-dir /home/netto/Desktop/redis-6.2.1/src -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-03-14-133648-8817-1 -x c listpack.c
1/* Listpack -- A lists of strings serialization format
2 *
3 * This file implements the specification you can find at:
4 *
5 * https://github.com/antirez/listpack
6 *
7 * Copyright (c) 2017, Salvatore Sanfilippo <antirez at gmail dot com>
8 * Copyright (c) 2020, Redis Labs, Inc
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * * Neither the name of Redis nor the names of its contributors may be used
20 * to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include <stdint.h>
37#include <limits.h>
38#include <sys/types.h>
39#include <stdlib.h>
40#include <string.h>
41#include <stdio.h>
42
43#include "listpack.h"
44#include "listpack_malloc.h"
45#include "redisassert.h"
46
47#define LP_HDR_SIZE6 6 /* 32 bit total len + 16 bit number of elements. */
48#define LP_HDR_NUMELE_UNKNOWN(65535) UINT16_MAX(65535)
49#define LP_MAX_INT_ENCODING_LEN9 9
50#define LP_MAX_BACKLEN_SIZE5 5
51#define LP_MAX_ENTRY_BACKLEN34359738367ULL 34359738367ULL
52#define LP_ENCODING_INT0 0
53#define LP_ENCODING_STRING1 1
54
55#define LP_ENCODING_7BIT_UINT0 0
56#define LP_ENCODING_7BIT_UINT_MASK0x80 0x80
57#define LP_ENCODING_IS_7BIT_UINT(byte)(((byte)&0x80)==0) (((byte)&LP_ENCODING_7BIT_UINT_MASK0x80)==LP_ENCODING_7BIT_UINT0)
58
59#define LP_ENCODING_6BIT_STR0x80 0x80
60#define LP_ENCODING_6BIT_STR_MASK0xC0 0xC0
61#define LP_ENCODING_IS_6BIT_STR(byte)(((byte)&0xC0)==0x80) (((byte)&LP_ENCODING_6BIT_STR_MASK0xC0)==LP_ENCODING_6BIT_STR0x80)
62
63#define LP_ENCODING_13BIT_INT0xC0 0xC0
64#define LP_ENCODING_13BIT_INT_MASK0xE0 0xE0
65#define LP_ENCODING_IS_13BIT_INT(byte)(((byte)&0xE0)==0xC0) (((byte)&LP_ENCODING_13BIT_INT_MASK0xE0)==LP_ENCODING_13BIT_INT0xC0)
66
67#define LP_ENCODING_12BIT_STR0xE0 0xE0
68#define LP_ENCODING_12BIT_STR_MASK0xF0 0xF0
69#define LP_ENCODING_IS_12BIT_STR(byte)(((byte)&0xF0)==0xE0) (((byte)&LP_ENCODING_12BIT_STR_MASK0xF0)==LP_ENCODING_12BIT_STR0xE0)
70
71#define LP_ENCODING_16BIT_INT0xF1 0xF1
72#define LP_ENCODING_16BIT_INT_MASK0xFF 0xFF
73#define LP_ENCODING_IS_16BIT_INT(byte)(((byte)&0xFF)==0xF1) (((byte)&LP_ENCODING_16BIT_INT_MASK0xFF)==LP_ENCODING_16BIT_INT0xF1)
74
75#define LP_ENCODING_24BIT_INT0xF2 0xF2
76#define LP_ENCODING_24BIT_INT_MASK0xFF 0xFF
77#define LP_ENCODING_IS_24BIT_INT(byte)(((byte)&0xFF)==0xF2) (((byte)&LP_ENCODING_24BIT_INT_MASK0xFF)==LP_ENCODING_24BIT_INT0xF2)
78
79#define LP_ENCODING_32BIT_INT0xF3 0xF3
80#define LP_ENCODING_32BIT_INT_MASK0xFF 0xFF
81#define LP_ENCODING_IS_32BIT_INT(byte)(((byte)&0xFF)==0xF3) (((byte)&LP_ENCODING_32BIT_INT_MASK0xFF)==LP_ENCODING_32BIT_INT0xF3)
82
83#define LP_ENCODING_64BIT_INT0xF4 0xF4
84#define LP_ENCODING_64BIT_INT_MASK0xFF 0xFF
85#define LP_ENCODING_IS_64BIT_INT(byte)(((byte)&0xFF)==0xF4) (((byte)&LP_ENCODING_64BIT_INT_MASK0xFF)==LP_ENCODING_64BIT_INT0xF4)
86
87#define LP_ENCODING_32BIT_STR0xF0 0xF0
88#define LP_ENCODING_32BIT_STR_MASK0xFF 0xFF
89#define LP_ENCODING_IS_32BIT_STR(byte)(((byte)&0xFF)==0xF0) (((byte)&LP_ENCODING_32BIT_STR_MASK0xFF)==LP_ENCODING_32BIT_STR0xF0)
90
91#define LP_EOF0xFF 0xFF
92
93#define LP_ENCODING_6BIT_STR_LEN(p)((p)[0] & 0x3F) ((p)[0] & 0x3F)
94#define LP_ENCODING_12BIT_STR_LEN(p)((((p)[0] & 0xF) << 8) | (p)[1]) ((((p)[0] & 0xF) << 8) | (p)[1])
95#define LP_ENCODING_32BIT_STR_LEN(p)(((uint32_t)(p)[1]<<0) | ((uint32_t)(p)[2]<<8) | (
(uint32_t)(p)[3]<<16) | ((uint32_t)(p)[4]<<24))
(((uint32_t)(p)[1]<<0) | \
96 ((uint32_t)(p)[2]<<8) | \
97 ((uint32_t)(p)[3]<<16) | \
98 ((uint32_t)(p)[4]<<24))
99
100#define lpGetTotalBytes(p)(((uint32_t)(p)[0]<<0) | ((uint32_t)(p)[1]<<8) | (
(uint32_t)(p)[2]<<16) | ((uint32_t)(p)[3]<<24))
(((uint32_t)(p)[0]<<0) | \
101 ((uint32_t)(p)[1]<<8) | \
102 ((uint32_t)(p)[2]<<16) | \
103 ((uint32_t)(p)[3]<<24))
104
105#define lpGetNumElements(p)(((uint32_t)(p)[4]<<0) | ((uint32_t)(p)[5]<<8)) (((uint32_t)(p)[4]<<0) | \
106 ((uint32_t)(p)[5]<<8))
107#define lpSetTotalBytes(p,v)do { (p)[0] = (v)&0xff; (p)[1] = ((v)>>8)&0xff;
(p)[2] = ((v)>>16)&0xff; (p)[3] = ((v)>>24)&
0xff; } while(0)
do { \
108 (p)[0] = (v)&0xff; \
109 (p)[1] = ((v)>>8)&0xff; \
110 (p)[2] = ((v)>>16)&0xff; \
111 (p)[3] = ((v)>>24)&0xff; \
112} while(0)
113
114#define lpSetNumElements(p,v)do { (p)[4] = (v)&0xff; (p)[5] = ((v)>>8)&0xff;
} while(0)
do { \
115 (p)[4] = (v)&0xff; \
116 (p)[5] = ((v)>>8)&0xff; \
117} while(0)
118
119/* Validates that 'p' is not ouside the listpack.
120 * All function that return a pointer to an element in the listpack will assert
121 * that this element is valid, so it can be freely used.
122 * Generally functions such lpNext and lpDelete assume the input pointer is
123 * already validated (since it's the return value of another function). */
124#define ASSERT_INTEGRITY(lp, p)do { (__builtin_expect(!!(((p) >= (lp)+6 && (p) <
(lp)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp))[1]<<
8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t)((lp))[3]<<
24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",124),__builtin_unreachable())); } while (0)
do { \
125 assert((p) >= (lp)+LP_HDR_SIZE && (p) < (lp)+lpGetTotalBytes((lp)))(__builtin_expect(!!(((p) >= (lp)+6 && (p) < (lp
)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp))[1]<<
8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t)((lp))[3]<<
24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",125),__builtin_unreachable()))
; \
126} while (0)
127
128/* Similar to the above, but validates the entire element lenth rather than just
129 * it's pointer. */
130#define ASSERT_INTEGRITY_LEN(lp, p, len)do { (__builtin_expect(!!(((p) >= (lp)+6 && (p)+(len
) < (lp)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp
))[1]<<8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t
)((lp))[3]<<24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p)+(len) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",130),__builtin_unreachable())); } while (0)
do { \
131 assert((p) >= (lp)+LP_HDR_SIZE && (p)+(len) < (lp)+lpGetTotalBytes((lp)))(__builtin_expect(!!(((p) >= (lp)+6 && (p)+(len) <
(lp)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp))[1]<<
8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t)((lp))[3]<<
24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p)+(len) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",131),__builtin_unreachable()))
; \
132} while (0)
133
134/* Convert a string into a signed 64 bit integer.
135 * The function returns 1 if the string could be parsed into a (non-overflowing)
136 * signed 64 bit int, 0 otherwise. The 'value' will be set to the parsed value
137 * when the function returns success.
138 *
139 * Note that this function demands that the string strictly represents
140 * a int64 value: no spaces or other characters before or after the string
141 * representing the number are accepted, nor zeroes at the start if not
142 * for the string "0" representing the zero number.
143 *
144 * Because of its strictness, it is safe to use this function to check if
145 * you can convert a string into a long long, and obtain back the string
146 * from the number without any loss in the string representation. *
147 *
148 * -----------------------------------------------------------------------------
149 *
150 * Credits: this function was adapted from the Redis source code, file
151 * "utils.c", function string2ll(), and is copyright:
152 *
153 * Copyright(C) 2011, Pieter Noordhuis
154 * Copyright(C) 2011, Salvatore Sanfilippo
155 *
156 * The function is released under the BSD 3-clause license.
157 */
158int lpStringToInt64(const char *s, unsigned long slen, int64_t *value) {
159 const char *p = s;
160 unsigned long plen = 0;
161 int negative = 0;
162 uint64_t v;
163
164 if (plen == slen)
165 return 0;
166
167 /* Special case: first and only digit is 0. */
168 if (slen == 1 && p[0] == '0') {
169 if (value != NULL((void*)0)) *value = 0;
170 return 1;
171 }
172
173 if (p[0] == '-') {
174 negative = 1;
175 p++; plen++;
176
177 /* Abort on only a negative sign. */
178 if (plen == slen)
179 return 0;
180 }
181
182 /* First digit should be 1-9, otherwise the string should just be 0. */
183 if (p[0] >= '1' && p[0] <= '9') {
184 v = p[0]-'0';
185 p++; plen++;
186 } else if (p[0] == '0' && slen == 1) {
187 *value = 0;
188 return 1;
189 } else {
190 return 0;
191 }
192
193 while (plen < slen && p[0] >= '0' && p[0] <= '9') {
194 if (v > (UINT64_MAX(18446744073709551615UL) / 10)) /* Overflow. */
195 return 0;
196 v *= 10;
197
198 if (v > (UINT64_MAX(18446744073709551615UL) - (p[0]-'0'))) /* Overflow. */
199 return 0;
200 v += p[0]-'0';
201
202 p++; plen++;
203 }
204
205 /* Return if not all bytes were used. */
206 if (plen < slen)
207 return 0;
208
209 if (negative) {
210 if (v > ((uint64_t)(-(INT64_MIN(-9223372036854775807L -1)+1))+1)) /* Overflow. */
211 return 0;
212 if (value != NULL((void*)0)) *value = -v;
213 } else {
214 if (v > INT64_MAX(9223372036854775807L)) /* Overflow. */
215 return 0;
216 if (value != NULL((void*)0)) *value = v;
217 }
218 return 1;
219}
220
221/* Create a new, empty listpack.
222 * On success the new listpack is returned, otherwise an error is returned.
223 * Pre-allocate at least `capacity` bytes of memory,
224 * over-allocated memory can be shrinked by `lpShrinkToFit`.
225 * */
226unsigned char *lpNew(size_t capacity) {
227 unsigned char *lp = lp_malloczmalloc(capacity > LP_HDR_SIZE6+1 ? capacity : LP_HDR_SIZE6+1);
228 if (lp == NULL((void*)0)) return NULL((void*)0);
229 lpSetTotalBytes(lp,LP_HDR_SIZE+1)do { (lp)[0] = (6 +1)&0xff; (lp)[1] = ((6 +1)>>8)&
0xff; (lp)[2] = ((6 +1)>>16)&0xff; (lp)[3] = ((6 +1
)>>24)&0xff; } while(0)
;
230 lpSetNumElements(lp,0)do { (lp)[4] = (0)&0xff; (lp)[5] = ((0)>>8)&0xff
; } while(0)
;
231 lp[LP_HDR_SIZE6] = LP_EOF0xFF;
232 return lp;
233}
234
235/* Free the specified listpack. */
236void lpFree(unsigned char *lp) {
237 lp_freezfree(lp);
238}
239
240/* Shrink the memory to fit. */
241unsigned char* lpShrinkToFit(unsigned char *lp) {
242 size_t size = lpGetTotalBytes(lp)(((uint32_t)(lp)[0]<<0) | ((uint32_t)(lp)[1]<<8) |
((uint32_t)(lp)[2]<<16) | ((uint32_t)(lp)[3]<<24
))
;
243 if (size < lp_malloc_size(lp)je_malloc_usable_size(lp)) {
244 return lp_realloczrealloc(lp, size);
245 } else {
246 return lp;
247 }
248}
249
250/* Given an element 'ele' of size 'size', determine if the element can be
251 * represented inside the listpack encoded as integer, and returns
252 * LP_ENCODING_INT if so. Otherwise returns LP_ENCODING_STR if no integer
253 * encoding is possible.
254 *
255 * If the LP_ENCODING_INT is returned, the function stores the integer encoded
256 * representation of the element in the 'intenc' buffer.
257 *
258 * Regardless of the returned encoding, 'enclen' is populated by reference to
259 * the number of bytes that the string or integer encoded element will require
260 * in order to be represented. */
261int lpEncodeGetType(unsigned char *ele, uint32_t size, unsigned char *intenc, uint64_t *enclen) {
262 int64_t v;
263 if (lpStringToInt64((const char*)ele, size, &v)) {
264 if (v >= 0 && v <= 127) {
265 /* Single byte 0-127 integer. */
266 intenc[0] = v;
267 *enclen = 1;
268 } else if (v >= -4096 && v <= 4095) {
269 /* 13 bit integer. */
270 if (v < 0) v = ((int64_t)1<<13)+v;
271 intenc[0] = (v>>8)|LP_ENCODING_13BIT_INT0xC0;
272 intenc[1] = v&0xff;
273 *enclen = 2;
274 } else if (v >= -32768 && v <= 32767) {
275 /* 16 bit integer. */
276 if (v < 0) v = ((int64_t)1<<16)+v;
277 intenc[0] = LP_ENCODING_16BIT_INT0xF1;
278 intenc[1] = v&0xff;
279 intenc[2] = v>>8;
280 *enclen = 3;
281 } else if (v >= -8388608 && v <= 8388607) {
282 /* 24 bit integer. */
283 if (v < 0) v = ((int64_t)1<<24)+v;
284 intenc[0] = LP_ENCODING_24BIT_INT0xF2;
285 intenc[1] = v&0xff;
286 intenc[2] = (v>>8)&0xff;
287 intenc[3] = v>>16;
288 *enclen = 4;
289 } else if (v >= -2147483648 && v <= 2147483647) {
290 /* 32 bit integer. */
291 if (v < 0) v = ((int64_t)1<<32)+v;
292 intenc[0] = LP_ENCODING_32BIT_INT0xF3;
293 intenc[1] = v&0xff;
294 intenc[2] = (v>>8)&0xff;
295 intenc[3] = (v>>16)&0xff;
296 intenc[4] = v>>24;
297 *enclen = 5;
298 } else {
299 /* 64 bit integer. */
300 uint64_t uv = v;
301 intenc[0] = LP_ENCODING_64BIT_INT0xF4;
302 intenc[1] = uv&0xff;
303 intenc[2] = (uv>>8)&0xff;
304 intenc[3] = (uv>>16)&0xff;
305 intenc[4] = (uv>>24)&0xff;
306 intenc[5] = (uv>>32)&0xff;
307 intenc[6] = (uv>>40)&0xff;
308 intenc[7] = (uv>>48)&0xff;
309 intenc[8] = uv>>56;
310 *enclen = 9;
311 }
312 return LP_ENCODING_INT0;
313 } else {
314 if (size < 64) *enclen = 1+size;
315 else if (size < 4096) *enclen = 2+size;
316 else *enclen = 5+size;
317 return LP_ENCODING_STRING1;
318 }
319}
320
321/* Store a reverse-encoded variable length field, representing the length
322 * of the previous element of size 'l', in the target buffer 'buf'.
323 * The function returns the number of bytes used to encode it, from
324 * 1 to 5. If 'buf' is NULL the function just returns the number of bytes
325 * needed in order to encode the backlen. */
326unsigned long lpEncodeBacklen(unsigned char *buf, uint64_t l) {
327 if (l <= 127) {
328 if (buf) buf[0] = l;
329 return 1;
330 } else if (l < 16383) {
331 if (buf) {
332 buf[0] = l>>7;
333 buf[1] = (l&127)|128;
334 }
335 return 2;
336 } else if (l < 2097151) {
337 if (buf) {
338 buf[0] = l>>14;
339 buf[1] = ((l>>7)&127)|128;
340 buf[2] = (l&127)|128;
341 }
342 return 3;
343 } else if (l < 268435455) {
344 if (buf) {
345 buf[0] = l>>21;
346 buf[1] = ((l>>14)&127)|128;
347 buf[2] = ((l>>7)&127)|128;
348 buf[3] = (l&127)|128;
349 }
350 return 4;
351 } else {
352 if (buf) {
353 buf[0] = l>>28;
354 buf[1] = ((l>>21)&127)|128;
355 buf[2] = ((l>>14)&127)|128;
356 buf[3] = ((l>>7)&127)|128;
357 buf[4] = (l&127)|128;
358 }
359 return 5;
360 }
361}
362
363/* Decode the backlen and returns it. If the encoding looks invalid (more than
364 * 5 bytes are used), UINT64_MAX is returned to report the problem. */
365uint64_t lpDecodeBacklen(unsigned char *p) {
366 uint64_t val = 0;
367 uint64_t shift = 0;
368 do {
369 val |= (uint64_t)(p[0] & 127) << shift;
370 if (!(p[0] & 128)) break;
371 shift += 7;
372 p--;
373 if (shift > 28) return UINT64_MAX(18446744073709551615UL);
374 } while(1);
375 return val;
376}
377
378/* Encode the string element pointed by 's' of size 'len' in the target
379 * buffer 's'. The function should be called with 'buf' having always enough
380 * space for encoding the string. This is done by calling lpEncodeGetType()
381 * before calling this function. */
382void lpEncodeString(unsigned char *buf, unsigned char *s, uint32_t len) {
383 if (len < 64) {
384 buf[0] = len | LP_ENCODING_6BIT_STR0x80;
385 memcpy(buf+1,s,len);
386 } else if (len < 4096) {
387 buf[0] = (len >> 8) | LP_ENCODING_12BIT_STR0xE0;
388 buf[1] = len & 0xff;
389 memcpy(buf+2,s,len);
390 } else {
391 buf[0] = LP_ENCODING_32BIT_STR0xF0;
392 buf[1] = len & 0xff;
393 buf[2] = (len >> 8) & 0xff;
394 buf[3] = (len >> 16) & 0xff;
395 buf[4] = (len >> 24) & 0xff;
396 memcpy(buf+5,s,len);
397 }
398}
399
400/* Return the encoded length of the listpack element pointed by 'p'.
401 * This includes the encoding byte, length bytes, and the element data itself.
402 * If the element encoding is wrong then 0 is returned.
403 * Note that this method may access additional bytes (in case of 12 and 32 bit
404 * str), so should only be called when we know 'p' was already validated by
405 * lpCurrentEncodedSizeBytes or ASSERT_INTEGRITY_LEN (possibly since 'p' is
406 * a return value of another function that validated its return. */
407uint32_t lpCurrentEncodedSizeUnsafe(unsigned char *p) {
408 if (LP_ENCODING_IS_7BIT_UINT(p[0])(((p[0])&0x80)==0)) return 1;
409 if (LP_ENCODING_IS_6BIT_STR(p[0])(((p[0])&0xC0)==0x80)) return 1+LP_ENCODING_6BIT_STR_LEN(p)((p)[0] & 0x3F);
410 if (LP_ENCODING_IS_13BIT_INT(p[0])(((p[0])&0xE0)==0xC0)) return 2;
411 if (LP_ENCODING_IS_16BIT_INT(p[0])(((p[0])&0xFF)==0xF1)) return 3;
412 if (LP_ENCODING_IS_24BIT_INT(p[0])(((p[0])&0xFF)==0xF2)) return 4;
413 if (LP_ENCODING_IS_32BIT_INT(p[0])(((p[0])&0xFF)==0xF3)) return 5;
414 if (LP_ENCODING_IS_64BIT_INT(p[0])(((p[0])&0xFF)==0xF4)) return 9;
415 if (LP_ENCODING_IS_12BIT_STR(p[0])(((p[0])&0xF0)==0xE0)) return 2+LP_ENCODING_12BIT_STR_LEN(p)((((p)[0] & 0xF) << 8) | (p)[1]);
416 if (LP_ENCODING_IS_32BIT_STR(p[0])(((p[0])&0xFF)==0xF0)) return 5+LP_ENCODING_32BIT_STR_LEN(p)(((uint32_t)(p)[1]<<0) | ((uint32_t)(p)[2]<<8) | (
(uint32_t)(p)[3]<<16) | ((uint32_t)(p)[4]<<24))
;
417 if (p[0] == LP_EOF0xFF) return 1;
418 return 0;
419}
420
421/* Return bytes needed to encode the length of the listpack element pointed by 'p'.
422 * This includes just the encodign byte, and the bytes needed to encode the length
423 * of the element (excluding the element data itself)
424 * If the element encoding is wrong then 0 is returned. */
425uint32_t lpCurrentEncodedSizeBytes(unsigned char *p) {
426 if (LP_ENCODING_IS_7BIT_UINT(p[0])(((p[0])&0x80)==0)) return 1;
427 if (LP_ENCODING_IS_6BIT_STR(p[0])(((p[0])&0xC0)==0x80)) return 1;
428 if (LP_ENCODING_IS_13BIT_INT(p[0])(((p[0])&0xE0)==0xC0)) return 1;
429 if (LP_ENCODING_IS_16BIT_INT(p[0])(((p[0])&0xFF)==0xF1)) return 1;
430 if (LP_ENCODING_IS_24BIT_INT(p[0])(((p[0])&0xFF)==0xF2)) return 1;
431 if (LP_ENCODING_IS_32BIT_INT(p[0])(((p[0])&0xFF)==0xF3)) return 1;
432 if (LP_ENCODING_IS_64BIT_INT(p[0])(((p[0])&0xFF)==0xF4)) return 1;
433 if (LP_ENCODING_IS_12BIT_STR(p[0])(((p[0])&0xF0)==0xE0)) return 2;
434 if (LP_ENCODING_IS_32BIT_STR(p[0])(((p[0])&0xFF)==0xF0)) return 5;
435 if (p[0] == LP_EOF0xFF) return 1;
436 return 0;
437}
438
439/* Skip the current entry returning the next. It is invalid to call this
440 * function if the current element is the EOF element at the end of the
441 * listpack, however, while this function is used to implement lpNext(),
442 * it does not return NULL when the EOF element is encountered. */
443unsigned char *lpSkip(unsigned char *p) {
444 unsigned long entrylen = lpCurrentEncodedSizeUnsafe(p);
445 entrylen += lpEncodeBacklen(NULL((void*)0),entrylen);
446 p += entrylen;
447 return p;
448}
449
450/* If 'p' points to an element of the listpack, calling lpNext() will return
451 * the pointer to the next element (the one on the right), or NULL if 'p'
452 * already pointed to the last element of the listpack. */
453unsigned char *lpNext(unsigned char *lp, unsigned char *p) {
454 assert(p)(__builtin_expect(!!((p)), 1)?(void)0 : (_serverAssert("p","listpack.c"
,454),__builtin_unreachable()))
;
455 p = lpSkip(p);
456 ASSERT_INTEGRITY(lp, p)do { (__builtin_expect(!!(((p) >= (lp)+6 && (p) <
(lp)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp))[1]<<
8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t)((lp))[3]<<
24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",456),__builtin_unreachable())); } while (0)
;
457 if (p[0] == LP_EOF0xFF) return NULL((void*)0);
458 return p;
459}
460
461/* If 'p' points to an element of the listpack, calling lpPrev() will return
462 * the pointer to the previous element (the one on the left), or NULL if 'p'
463 * already pointed to the first element of the listpack. */
464unsigned char *lpPrev(unsigned char *lp, unsigned char *p) {
465 assert(p)(__builtin_expect(!!((p)), 1)?(void)0 : (_serverAssert("p","listpack.c"
,465),__builtin_unreachable()))
;
466 if (p-lp == LP_HDR_SIZE6) return NULL((void*)0);
467 p--; /* Seek the first backlen byte of the last element. */
468 uint64_t prevlen = lpDecodeBacklen(p);
469 prevlen += lpEncodeBacklen(NULL((void*)0),prevlen);
470 p -= prevlen-1; /* Seek the first byte of the previous entry. */
471 ASSERT_INTEGRITY(lp, p)do { (__builtin_expect(!!(((p) >= (lp)+6 && (p) <
(lp)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp))[1]<<
8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t)((lp))[3]<<
24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",471),__builtin_unreachable())); } while (0)
;
472 return p;
473}
474
475/* Return a pointer to the first element of the listpack, or NULL if the
476 * listpack has no elements. */
477unsigned char *lpFirst(unsigned char *lp) {
478 lp += LP_HDR_SIZE6; /* Skip the header. */
479 if (lp[0] == LP_EOF0xFF) return NULL((void*)0);
480 return lp;
481}
482
483/* Return a pointer to the last element of the listpack, or NULL if the
484 * listpack has no elements. */
485unsigned char *lpLast(unsigned char *lp) {
486 unsigned char *p = lp+lpGetTotalBytes(lp)(((uint32_t)(lp)[0]<<0) | ((uint32_t)(lp)[1]<<8) |
((uint32_t)(lp)[2]<<16) | ((uint32_t)(lp)[3]<<24
))
-1; /* Seek EOF element. */
487 return lpPrev(lp,p); /* Will return NULL if EOF is the only element. */
488}
489
490/* Return the number of elements inside the listpack. This function attempts
491 * to use the cached value when within range, otherwise a full scan is
492 * needed. As a side effect of calling this function, the listpack header
493 * could be modified, because if the count is found to be already within
494 * the 'numele' header field range, the new value is set. */
495uint32_t lpLength(unsigned char *lp) {
496 uint32_t numele = lpGetNumElements(lp)(((uint32_t)(lp)[4]<<0) | ((uint32_t)(lp)[5]<<8));
497 if (numele != LP_HDR_NUMELE_UNKNOWN(65535)) return numele;
498
499 /* Too many elements inside the listpack. We need to scan in order
500 * to get the total number. */
501 uint32_t count = 0;
502 unsigned char *p = lpFirst(lp);
503 while(p) {
504 count++;
505 p = lpNext(lp,p);
506 }
507
508 /* If the count is again within range of the header numele field,
509 * set it. */
510 if (count < LP_HDR_NUMELE_UNKNOWN(65535)) lpSetNumElements(lp,count)do { (lp)[4] = (count)&0xff; (lp)[5] = ((count)>>8)
&0xff; } while(0)
;
511 return count;
512}
513
514/* Return the listpack element pointed by 'p'.
515 *
516 * The function changes behavior depending on the passed 'intbuf' value.
517 * Specifically, if 'intbuf' is NULL:
518 *
519 * If the element is internally encoded as an integer, the function returns
520 * NULL and populates the integer value by reference in 'count'. Otherwise if
521 * the element is encoded as a string a pointer to the string (pointing inside
522 * the listpack itself) is returned, and 'count' is set to the length of the
523 * string.
524 *
525 * If instead 'intbuf' points to a buffer passed by the caller, that must be
526 * at least LP_INTBUF_SIZE bytes, the function always returns the element as
527 * it was a string (returning the pointer to the string and setting the
528 * 'count' argument to the string length by reference). However if the element
529 * is encoded as an integer, the 'intbuf' buffer is used in order to store
530 * the string representation.
531 *
532 * The user should use one or the other form depending on what the value will
533 * be used for. If there is immediate usage for an integer value returned
534 * by the function, than to pass a buffer (and convert it back to a number)
535 * is of course useless.
536 *
537 * If the function is called against a badly encoded ziplist, so that there
538 * is no valid way to parse it, the function returns like if there was an
539 * integer encoded with value 12345678900000000 + <unrecognized byte>, this may
540 * be an hint to understand that something is wrong. To crash in this case is
541 * not sensible because of the different requirements of the application using
542 * this lib.
543 *
544 * Similarly, there is no error returned since the listpack normally can be
545 * assumed to be valid, so that would be a very high API cost. However a function
546 * in order to check the integrity of the listpack at load time is provided,
547 * check lpIsValid(). */
548unsigned char *lpGet(unsigned char *p, int64_t *count, unsigned char *intbuf) {
549 int64_t val;
550 uint64_t uval, negstart, negmax;
551
552 assert(p)(__builtin_expect(!!((p)), 1)?(void)0 : (_serverAssert("p","listpack.c"
,552),__builtin_unreachable()))
; /* assertion for valgrind (avoid NPD) */
553 if (LP_ENCODING_IS_7BIT_UINT(p[0])(((p[0])&0x80)==0)) {
554 negstart = UINT64_MAX(18446744073709551615UL); /* 7 bit ints are always positive. */
555 negmax = 0;
556 uval = p[0] & 0x7f;
557 } else if (LP_ENCODING_IS_6BIT_STR(p[0])(((p[0])&0xC0)==0x80)) {
558 *count = LP_ENCODING_6BIT_STR_LEN(p)((p)[0] & 0x3F);
559 return p+1;
560 } else if (LP_ENCODING_IS_13BIT_INT(p[0])(((p[0])&0xE0)==0xC0)) {
561 uval = ((p[0]&0x1f)<<8) | p[1];
562 negstart = (uint64_t)1<<12;
563 negmax = 8191;
564 } else if (LP_ENCODING_IS_16BIT_INT(p[0])(((p[0])&0xFF)==0xF1)) {
565 uval = (uint64_t)p[1] |
566 (uint64_t)p[2]<<8;
567 negstart = (uint64_t)1<<15;
568 negmax = UINT16_MAX(65535);
569 } else if (LP_ENCODING_IS_24BIT_INT(p[0])(((p[0])&0xFF)==0xF2)) {
570 uval = (uint64_t)p[1] |
571 (uint64_t)p[2]<<8 |
572 (uint64_t)p[3]<<16;
573 negstart = (uint64_t)1<<23;
574 negmax = UINT32_MAX(4294967295U)>>8;
575 } else if (LP_ENCODING_IS_32BIT_INT(p[0])(((p[0])&0xFF)==0xF3)) {
576 uval = (uint64_t)p[1] |
577 (uint64_t)p[2]<<8 |
578 (uint64_t)p[3]<<16 |
579 (uint64_t)p[4]<<24;
580 negstart = (uint64_t)1<<31;
581 negmax = UINT32_MAX(4294967295U);
582 } else if (LP_ENCODING_IS_64BIT_INT(p[0])(((p[0])&0xFF)==0xF4)) {
583 uval = (uint64_t)p[1] |
584 (uint64_t)p[2]<<8 |
585 (uint64_t)p[3]<<16 |
586 (uint64_t)p[4]<<24 |
587 (uint64_t)p[5]<<32 |
588 (uint64_t)p[6]<<40 |
589 (uint64_t)p[7]<<48 |
590 (uint64_t)p[8]<<56;
591 negstart = (uint64_t)1<<63;
592 negmax = UINT64_MAX(18446744073709551615UL);
593 } else if (LP_ENCODING_IS_12BIT_STR(p[0])(((p[0])&0xF0)==0xE0)) {
594 *count = LP_ENCODING_12BIT_STR_LEN(p)((((p)[0] & 0xF) << 8) | (p)[1]);
595 return p+2;
596 } else if (LP_ENCODING_IS_32BIT_STR(p[0])(((p[0])&0xFF)==0xF0)) {
597 *count = LP_ENCODING_32BIT_STR_LEN(p)(((uint32_t)(p)[1]<<0) | ((uint32_t)(p)[2]<<8) | (
(uint32_t)(p)[3]<<16) | ((uint32_t)(p)[4]<<24))
;
598 return p+5;
599 } else {
600 uval = 12345678900000000ULL + p[0];
601 negstart = UINT64_MAX(18446744073709551615UL);
602 negmax = 0;
603 }
604
605 /* We reach this code path only for integer encodings.
606 * Convert the unsigned value to the signed one using two's complement
607 * rule. */
608 if (uval >= negstart) {
609 /* This three steps conversion should avoid undefined behaviors
610 * in the unsigned -> signed conversion. */
611 uval = negmax-uval;
612 val = uval;
613 val = -val-1;
614 } else {
615 val = uval;
616 }
617
618 /* Return the string representation of the integer or the value itself
619 * depending on intbuf being NULL or not. */
620 if (intbuf) {
621 *count = snprintf((char*)intbuf,LP_INTBUF_SIZE21,"%lld",(long long)val);
622 return intbuf;
623 } else {
624 *count = val;
625 return NULL((void*)0);
626 }
627}
628
629/* Insert, delete or replace the specified element 'ele' of length 'len' at
630 * the specified position 'p', with 'p' being a listpack element pointer
631 * obtained with lpFirst(), lpLast(), lpNext(), lpPrev() or lpSeek().
632 *
633 * The element is inserted before, after, or replaces the element pointed
634 * by 'p' depending on the 'where' argument, that can be LP_BEFORE, LP_AFTER
635 * or LP_REPLACE.
636 *
637 * If 'ele' is set to NULL, the function removes the element pointed by 'p'
638 * instead of inserting one.
639 *
640 * Returns NULL on out of memory or when the listpack total length would exceed
641 * the max allowed size of 2^32-1, otherwise the new pointer to the listpack
642 * holding the new element is returned (and the old pointer passed is no longer
643 * considered valid)
644 *
645 * If 'newp' is not NULL, at the end of a successful call '*newp' will be set
646 * to the address of the element just added, so that it will be possible to
647 * continue an interation with lpNext() and lpPrev().
648 *
649 * For deletion operations ('ele' set to NULL) 'newp' is set to the next
650 * element, on the right of the deleted one, or to NULL if the deleted element
651 * was the last one. */
652unsigned char *lpInsert(unsigned char *lp, unsigned char *ele, uint32_t size, unsigned char *p, int where, unsigned char **newp) {
653 unsigned char intenc[LP_MAX_INT_ENCODING_LEN9];
654 unsigned char backlen[LP_MAX_BACKLEN_SIZE5];
655
656 uint64_t enclen; /* The length of the encoded element. */
657
658 /* An element pointer set to NULL means deletion, which is conceptually
659 * replacing the element with a zero-length element. So whatever we
660 * get passed as 'where', set it to LP_REPLACE. */
661 if (ele == NULL((void*)0)) where = LP_REPLACE2;
662
663 /* If we need to insert after the current element, we just jump to the
664 * next element (that could be the EOF one) and handle the case of
665 * inserting before. So the function will actually deal with just two
666 * cases: LP_BEFORE and LP_REPLACE. */
667 if (where == LP_AFTER1) {
668 p = lpSkip(p);
669 where = LP_BEFORE0;
670 ASSERT_INTEGRITY(lp, p)do { (__builtin_expect(!!(((p) >= (lp)+6 && (p) <
(lp)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp))[1]<<
8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t)((lp))[3]<<
24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",670),__builtin_unreachable())); } while (0)
;
671 }
672
673 /* Store the offset of the element 'p', so that we can obtain its
674 * address again after a reallocation. */
675 unsigned long poff = p-lp;
676
677 /* Calling lpEncodeGetType() results into the encoded version of the
678 * element to be stored into 'intenc' in case it is representable as
679 * an integer: in that case, the function returns LP_ENCODING_INT.
680 * Otherwise if LP_ENCODING_STR is returned, we'll have to call
681 * lpEncodeString() to actually write the encoded string on place later.
682 *
683 * Whatever the returned encoding is, 'enclen' is populated with the
684 * length of the encoded element. */
685 int enctype;
686 if (ele) {
687 enctype = lpEncodeGetType(ele,size,intenc,&enclen);
688 } else {
689 enctype = -1;
690 enclen = 0;
691 }
692
693 /* We need to also encode the backward-parsable length of the element
694 * and append it to the end: this allows to traverse the listpack from
695 * the end to the start. */
696 unsigned long backlen_size = ele ? lpEncodeBacklen(backlen,enclen) : 0;
697 uint64_t old_listpack_bytes = lpGetTotalBytes(lp)(((uint32_t)(lp)[0]<<0) | ((uint32_t)(lp)[1]<<8) |
((uint32_t)(lp)[2]<<16) | ((uint32_t)(lp)[3]<<24
))
;
698 uint32_t replaced_len = 0;
699 if (where == LP_REPLACE2) {
700 replaced_len = lpCurrentEncodedSizeUnsafe(p);
701 replaced_len += lpEncodeBacklen(NULL((void*)0),replaced_len);
702 ASSERT_INTEGRITY_LEN(lp, p, replaced_len)do { (__builtin_expect(!!(((p) >= (lp)+6 && (p)+(replaced_len
) < (lp)+(((uint32_t)((lp))[0]<<0) | ((uint32_t)((lp
))[1]<<8) | ((uint32_t)((lp))[2]<<16) | ((uint32_t
)((lp))[3]<<24)))), 1)?(void)0 : (_serverAssert("(p) >= (lp)+LP_HDR_SIZE && (p)+(replaced_len) < (lp)+lpGetTotalBytes((lp))"
,"listpack.c",702),__builtin_unreachable())); } while (0)
;
703 }
704
705 uint64_t new_listpack_bytes = old_listpack_bytes + enclen + backlen_size
706 - replaced_len;
707 if (new_listpack_bytes > UINT32_MAX(4294967295U)) return NULL((void*)0);
708
709 /* We now need to reallocate in order to make space or shrink the
710 * allocation (in case 'when' value is LP_REPLACE and the new element is
711 * smaller). However we do that before memmoving the memory to
712 * make room for the new element if the final allocation will get
713 * larger, or we do it after if the final allocation will get smaller. */
714
715 unsigned char *dst = lp + poff; /* May be updated after reallocation. */
716
717 /* Realloc before: we need more room. */
718 if (new_listpack_bytes > old_listpack_bytes &&
719 new_listpack_bytes > lp_malloc_size(lp)je_malloc_usable_size(lp)) {
720 if ((lp = lp_realloczrealloc(lp,new_listpack_bytes)) == NULL((void*)0)) return NULL((void*)0);
721 dst = lp + poff;
722 }
723
724 /* Setup the listpack relocating the elements to make the exact room
725 * we need to store the new one. */
726 if (where == LP_BEFORE0) {
727 memmove(dst+enclen+backlen_size,dst,old_listpack_bytes-poff);
728 } else { /* LP_REPLACE. */
729 long lendiff = (enclen+backlen_size)-replaced_len;
730 memmove(dst+replaced_len+lendiff,
731 dst+replaced_len,
732 old_listpack_bytes-poff-replaced_len);
733 }
734
735 /* Realloc after: we need to free space. */
736 if (new_listpack_bytes < old_listpack_bytes) {
737 if ((lp = lp_realloczrealloc(lp,new_listpack_bytes)) == NULL((void*)0)) return NULL((void*)0);
738 dst = lp + poff;
739 }
740
741 /* Store the entry. */
742 if (newp) {
743 *newp = dst;
744 /* In case of deletion, set 'newp' to NULL if the next element is
745 * the EOF element. */
746 if (!ele && dst[0] == LP_EOF0xFF) *newp = NULL((void*)0);
747 }
748 if (ele) {
749 if (enctype == LP_ENCODING_INT0) {
750 memcpy(dst,intenc,enclen);
751 } else {
752 lpEncodeString(dst,ele,size);
753 }
754 dst += enclen;
755 memcpy(dst,backlen,backlen_size);
756 dst += backlen_size;
Value stored to 'dst' is never read
757 }
758
759 /* Update header. */
760 if (where != LP_REPLACE2 || ele == NULL((void*)0)) {
761 uint32_t num_elements = lpGetNumElements(lp)(((uint32_t)(lp)[4]<<0) | ((uint32_t)(lp)[5]<<8));
762 if (num_elements != LP_HDR_NUMELE_UNKNOWN(65535)) {
763 if (ele)
764 lpSetNumElements(lp,num_elements+1)do { (lp)[4] = (num_elements+1)&0xff; (lp)[5] = ((num_elements
+1)>>8)&0xff; } while(0)
;
765 else
766 lpSetNumElements(lp,num_elements-1)do { (lp)[4] = (num_elements-1)&0xff; (lp)[5] = ((num_elements
-1)>>8)&0xff; } while(0)
;
767 }
768 }
769 lpSetTotalBytes(lp,new_listpack_bytes)do { (lp)[0] = (new_listpack_bytes)&0xff; (lp)[1] = ((new_listpack_bytes
)>>8)&0xff; (lp)[2] = ((new_listpack_bytes)>>
16)&0xff; (lp)[3] = ((new_listpack_bytes)>>24)&
0xff; } while(0)
;
770
771#if 0
772 /* This code path is normally disabled: what it does is to force listpack
773 * to return *always* a new pointer after performing some modification to
774 * the listpack, even if the previous allocation was enough. This is useful
775 * in order to spot bugs in code using listpacks: by doing so we can find
776 * if the caller forgets to set the new pointer where the listpack reference
777 * is stored, after an update. */
778 unsigned char *oldlp = lp;
779 lp = lp_malloczmalloc(new_listpack_bytes);
780 memcpy(lp,oldlp,new_listpack_bytes);
781 if (newp) {
782 unsigned long offset = (*newp)-oldlp;
783 *newp = lp + offset;
784 }
785 /* Make sure the old allocation contains garbage. */
786 memset(oldlp,'A',new_listpack_bytes);
787 lp_freezfree(oldlp);
788#endif
789
790 return lp;
791}
792
793/* Append the specified element 'ele' of length 'len' at the end of the
794 * listpack. It is implemented in terms of lpInsert(), so the return value is
795 * the same as lpInsert(). */
796unsigned char *lpAppend(unsigned char *lp, unsigned char *ele, uint32_t size) {
797 uint64_t listpack_bytes = lpGetTotalBytes(lp)(((uint32_t)(lp)[0]<<0) | ((uint32_t)(lp)[1]<<8) |
((uint32_t)(lp)[2]<<16) | ((uint32_t)(lp)[3]<<24
))
;
798 unsigned char *eofptr = lp + listpack_bytes - 1;
799 return lpInsert(lp,ele,size,eofptr,LP_BEFORE0,NULL((void*)0));
800}
801
802/* Remove the element pointed by 'p', and return the resulting listpack.
803 * If 'newp' is not NULL, the next element pointer (to the right of the
804 * deleted one) is returned by reference. If the deleted element was the
805 * last one, '*newp' is set to NULL. */
806unsigned char *lpDelete(unsigned char *lp, unsigned char *p, unsigned char **newp) {
807 return lpInsert(lp,NULL((void*)0),0,p,LP_REPLACE2,newp);
808}
809
810/* Return the total number of bytes the listpack is composed of. */
811uint32_t lpBytes(unsigned char *lp) {
812 return lpGetTotalBytes(lp)(((uint32_t)(lp)[0]<<0) | ((uint32_t)(lp)[1]<<8) |
((uint32_t)(lp)[2]<<16) | ((uint32_t)(lp)[3]<<24
))
;
813}
814
815/* Seek the specified element and returns the pointer to the seeked element.
816 * Positive indexes specify the zero-based element to seek from the head to
817 * the tail, negative indexes specify elements starting from the tail, where
818 * -1 means the last element, -2 the penultimate and so forth. If the index
819 * is out of range, NULL is returned. */
820unsigned char *lpSeek(unsigned char *lp, long index) {
821 int forward = 1; /* Seek forward by default. */
822
823 /* We want to seek from left to right or the other way around
824 * depending on the listpack length and the element position.
825 * However if the listpack length cannot be obtained in constant time,
826 * we always seek from left to right. */
827 uint32_t numele = lpGetNumElements(lp)(((uint32_t)(lp)[4]<<0) | ((uint32_t)(lp)[5]<<8));
828 if (numele != LP_HDR_NUMELE_UNKNOWN(65535)) {
829 if (index < 0) index = (long)numele+index;
830 if (index < 0) return NULL((void*)0); /* Index still < 0 means out of range. */
831 if (index >= (long)numele) return NULL((void*)0); /* Out of range the other side. */
832 /* We want to scan right-to-left if the element we are looking for
833 * is past the half of the listpack. */
834 if (index > (long)numele/2) {
835 forward = 0;
836 /* Right to left scanning always expects a negative index. Convert
837 * our index to negative form. */
838 index -= numele;
839 }
840 } else {
841 /* If the listpack length is unspecified, for negative indexes we
842 * want to always scan right-to-left. */
843 if (index < 0) forward = 0;
844 }
845
846 /* Forward and backward scanning is trivially based on lpNext()/lpPrev(). */
847 if (forward) {
848 unsigned char *ele = lpFirst(lp);
849 while (index > 0 && ele) {
850 ele = lpNext(lp,ele);
851 index--;
852 }
853 return ele;
854 } else {
855 unsigned char *ele = lpLast(lp);
856 while (index < -1 && ele) {
857 ele = lpPrev(lp,ele);
858 index++;
859 }
860 return ele;
861 }
862}
863
864/* Validate the integrity of a single listpack entry and move to the next one.
865 * The input argument 'pp' is a reference to the current record and is advanced on exit.
866 * Returns 1 if valid, 0 if invalid. */
867int lpValidateNext(unsigned char *lp, unsigned char **pp, size_t lpbytes) {
868#define OUT_OF_RANGE(p) ( \
869 (p) < lp + LP_HDR_SIZE6 || \
870 (p) > lp + lpbytes - 1)
871 unsigned char *p = *pp;
872 if (!p)
873 return 0;
874
875 if (*p == LP_EOF0xFF) {
876 *pp = NULL((void*)0);
877 return 1;
878 }
879
880 /* check that we can read the encoded size */
881 uint32_t lenbytes = lpCurrentEncodedSizeBytes(p);
882 if (!lenbytes)
883 return 0;
884
885 /* make sure the encoded entry length doesn't rech outside the edge of the listpack */
886 if (OUT_OF_RANGE(p + lenbytes))
887 return 0;
888
889 /* get the entry length and encoded backlen. */
890 unsigned long entrylen = lpCurrentEncodedSizeUnsafe(p);
891 unsigned long encodedBacklen = lpEncodeBacklen(NULL((void*)0),entrylen);
892 entrylen += encodedBacklen;
893
894 /* make sure the entry doesn't rech outside the edge of the listpack */
895 if (OUT_OF_RANGE(p + entrylen))
896 return 0;
897
898 /* move to the next entry */
899 p += entrylen;
900
901 /* make sure the encoded length at the end patches the one at the beginning. */
902 uint64_t prevlen = lpDecodeBacklen(p-1);
903 if (prevlen + encodedBacklen != entrylen)
904 return 0;
905
906 *pp = p;
907 return 1;
908#undef OUT_OF_RANGE
909}
910
911/* Validate the integrity of the data stracture.
912 * when `deep` is 0, only the integrity of the header is validated.
913 * when `deep` is 1, we scan all the entries one by one. */
914int lpValidateIntegrity(unsigned char *lp, size_t size, int deep){
915 /* Check that we can actually read the header. (and EOF) */
916 if (size < LP_HDR_SIZE6 + 1)
917 return 0;
918
919 /* Check that the encoded size in the header must match the allocated size. */
920 size_t bytes = lpGetTotalBytes(lp)(((uint32_t)(lp)[0]<<0) | ((uint32_t)(lp)[1]<<8) |
((uint32_t)(lp)[2]<<16) | ((uint32_t)(lp)[3]<<24
))
;
921 if (bytes != size)
922 return 0;
923
924 /* The last byte must be the terminator. */
925 if (lp[size-1] != LP_EOF0xFF)
926 return 0;
927
928 if (!deep)
929 return 1;
930
931 /* Validate the invividual entries. */
932 uint32_t count = 0;
933 unsigned char *p = lpFirst(lp);
934 while(p) {
935 if (!lpValidateNext(lp, &p, bytes))
936 return 0;
937 count++;
938 }
939
940 /* Check that the count in the header is correct */
941 uint32_t numele = lpGetNumElements(lp)(((uint32_t)(lp)[4]<<0) | ((uint32_t)(lp)[5]<<8));
942 if (numele != LP_HDR_NUMELE_UNKNOWN(65535) && numele != count)
943 return 0;
944
945 return 1;
946}