Skip to content
This repository
Browse code

Fix c->reply_bytes computation in setDeferredMultiBulkLength()

In order to implement reply buffer limits introduced in 2.6 and useful
to close the connection under user-selected circumastances of big output
buffers (for instance slow consumers in pub/sub, a blocked slave, and so
forth) Redis takes a counter with the amount of used memory in objects
inside the output list stored into c->reply.

The computation was broken in the function setDeferredMultiBulkLength(),
in the case the object was glued with the next one. This caused the
c->reply_bytes field to go out of sync, be subtracted more than needed,
and wrap back near to ULONG_MAX values.

This commit fixes this bug and adds an assertion that is able to trap
this class of problems.

This problem was discovered looking at the INFO output of an unrelated
issue (issue #547).
  • Loading branch information...
commit 6fe9c402a2b9dcd3cb1a15aed08a86338ec143f3 1 parent 8361d6c
Salvatore Sanfilippo authored June 15, 2012

Showing 1 changed file with 4 additions and 0 deletions. Show diff stats Hide diff stats

  1. 4  src/networking.c
4  src/networking.c
@@ -364,7 +364,10 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
364 364
 
365 365
         /* Only glue when the next node is non-NULL (an sds in this case) */
366 366
         if (next->ptr != NULL) {
  367
+            c->reply_bytes -= zmalloc_size_sds(len->ptr);
  368
+            c->reply_bytes -= zmalloc_size_sds(next->ptr);
367 369
             len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
  370
+            c->reply_bytes += zmalloc_size_sds(len->ptr);
368 371
             listDelNode(c->reply,ln->next);
369 372
         }
370 373
     }
@@ -1302,6 +1305,7 @@ int checkClientOutputBufferLimits(redisClient *c) {
1302 1305
  * called from contexts where the client can't be freed safely, i.e. from the
1303 1306
  * lower level functions pushing data inside the client output buffers. */
1304 1307
 void asyncCloseClientOnOutputBufferLimitReached(redisClient *c) {
  1308
+    redisAssert(c->reply_bytes < ULONG_MAX-(1024*64));
1305 1309
     if (c->reply_bytes == 0 || c->flags & REDIS_CLOSE_ASAP) return;
1306 1310
     if (checkClientOutputBufferLimits(c)) {
1307 1311
         sds client = getClientInfoString(c);

0 notes on commit 6fe9c40

Please sign in to comment.
Something went wrong with that request. Please try again.