39
39
#include <assert.h>
40
40
#include <errno.h>
41
41
#include <ctype.h>
42
+ #include <limits.h>
42
43
43
44
#include "read.h"
44
45
#include "sds.h"
@@ -142,32 +143,24 @@ static char *seekNewline(char *s, size_t len) {
142
143
}
143
144
144
145
/* Read a long long value starting at *s, under the assumption that it will be
145
- * terminated by \r\n. Ambiguously returns -1 for unexpected input. */
146
- static long long readLongLong (char * s ) {
147
- long long v = 0 ;
148
- int dec , mult = 1 ;
149
- char c ;
150
-
151
- if (* s == '-' ) {
152
- mult = -1 ;
153
- s ++ ;
154
- } else if (* s == '+' ) {
155
- mult = 1 ;
156
- s ++ ;
146
+ * terminated by \r\n. Returns REDIS_ERR for unexpected inputs or if the
147
+ * resulting value would be greater than LLONG_MAX. */
148
+ static int readLongLong (char * s , long long * val ) {
149
+ char * end ;
150
+ errno = 0 ;
151
+
152
+ long long v = strtoll (s , & end , 10 );
153
+
154
+ if (s == end || ((v == LLONG_MAX || v == LLONG_MIN ) && errno == ERANGE )
155
+ || (* end != '\r' || * (end + 1 ) != '\n' )) {
156
+ return REDIS_ERR ;
157
157
}
158
158
159
- while ((c = * (s ++ )) != '\r' ) {
160
- dec = c - '0' ;
161
- if (dec >= 0 && dec < 10 ) {
162
- v *= 10 ;
163
- v += dec ;
164
- } else {
165
- /* Should not happen... */
166
- return -1 ;
167
- }
159
+ if (val ) {
160
+ * val = v ;
168
161
}
169
162
170
- return mult * v ;
163
+ return REDIS_OK ;
171
164
}
172
165
173
166
static char * readLine (redisReader * r , int * _len ) {
@@ -218,10 +211,17 @@ static int processLineItem(redisReader *r) {
218
211
219
212
if ((p = readLine (r ,& len )) != NULL ) {
220
213
if (cur -> type == REDIS_REPLY_INTEGER ) {
221
- if (r -> fn && r -> fn -> createInteger )
222
- obj = r -> fn -> createInteger (cur ,readLongLong (p ));
223
- else
214
+ if (r -> fn && r -> fn -> createInteger ) {
215
+ long long v ;
216
+ if (readLongLong (p , & v ) == REDIS_ERR ) {
217
+ __redisReaderSetError (r ,REDIS_ERR_PROTOCOL ,
218
+ "Bad integer value" );
219
+ return REDIS_ERR ;
220
+ }
221
+ obj = r -> fn -> createInteger (cur ,v );
222
+ } else {
224
223
obj = (void * )REDIS_REPLY_INTEGER ;
224
+ }
225
225
} else {
226
226
/* Type will be error or status. */
227
227
if (r -> fn && r -> fn -> createString )
@@ -248,7 +248,7 @@ static int processBulkItem(redisReader *r) {
248
248
redisReadTask * cur = & (r -> rstack [r -> ridx ]);
249
249
void * obj = NULL ;
250
250
char * p , * s ;
251
- long len ;
251
+ long long len ;
252
252
unsigned long bytelen ;
253
253
int success = 0 ;
254
254
@@ -257,7 +257,12 @@ static int processBulkItem(redisReader *r) {
257
257
if (s != NULL ) {
258
258
p = r -> buf + r -> pos ;
259
259
bytelen = s - (r -> buf + r -> pos )+ 2 ; /* include \r\n */
260
- len = readLongLong (p );
260
+
261
+ if (readLongLong (p , & len ) == REDIS_ERR ) {
262
+ __redisReaderSetError (r ,REDIS_ERR_PROTOCOL ,
263
+ "Bad bulk string length" );
264
+ return REDIS_ERR ;
265
+ }
261
266
262
267
if (len < 0 ) {
263
268
/* The nil object can always be created. */
@@ -301,7 +306,7 @@ static int processMultiBulkItem(redisReader *r) {
301
306
redisReadTask * cur = & (r -> rstack [r -> ridx ]);
302
307
void * obj ;
303
308
char * p ;
304
- long elements ;
309
+ long long elements ;
305
310
int root = 0 ;
306
311
307
312
/* Set error for nested multi bulks with depth > 7 */
@@ -312,7 +317,12 @@ static int processMultiBulkItem(redisReader *r) {
312
317
}
313
318
314
319
if ((p = readLine (r ,NULL )) != NULL ) {
315
- elements = readLongLong (p );
320
+ if (readLongLong (p , & elements ) == REDIS_ERR ) {
321
+ __redisReaderSetError (r ,REDIS_ERR_PROTOCOL ,
322
+ "Bad multi-bulk length" );
323
+ return REDIS_ERR ;
324
+ }
325
+
316
326
root = (r -> ridx == 0 );
317
327
318
328
if (elements == -1 ) {
0 commit comments