Skip to content

Commit 2e6b05f

Browse files
author
Ruben Bridgewater
committed
Fix buffer corruption
Fixes #6 Add changelog entry
1 parent 22fab6d commit 2e6b05f

File tree

3 files changed

+61
-30
lines changed

3 files changed

+61
-30
lines changed

changelog.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
## v.2.0.1 - 0x Jun, 2016
1+
## v.2.0.2 - 08 Jun, 2016
2+
3+
Bugfixes
4+
5+
- Fixed parser with returnBuffers option returning corrupted data
6+
7+
## v.2.0.1 - 04 Jun, 2016
28

39
Bugfixes
410

lib/parser.js

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use strict'
22

33
var ReplyError = require('./replyError')
4-
var bufferPool = new Buffer(64 * 1024)
4+
var bufferPool = new Buffer(32 * 1024)
5+
var bufferOffset = 0
56
var interval = null
67

78
/**
@@ -135,6 +136,9 @@ function parseBulkString (parser) {
135136
var offsetEnd = parser.offset + length
136137
if (offsetEnd + 2 > parser.buffer.length) {
137138
parser.bigStrSize = offsetEnd + 2
139+
parser.bigOffset = parser.offset
140+
parser.totalChunkSize = parser.buffer.length
141+
parser.bufferCache.push(parser.buffer)
138142
return
139143
}
140144

@@ -320,18 +324,26 @@ function decreaseBufferPool () {
320324
*/
321325
function concatBuffer (parser, length) {
322326
var list = parser.bufferCache
323-
var pos = 0
324-
if (bufferPool.length < length) {
325-
bufferPool = new Buffer(length)
327+
var pos = bufferOffset
328+
length -= parser.offset
329+
if (bufferPool.length < length + bufferOffset) {
330+
// Increase the bufferPool size by three times the current needed length
331+
bufferPool = new Buffer(length * 3 + bufferOffset)
332+
bufferOffset = 0
333+
pos = 0
326334
if (interval === null) {
327-
interval = setInterval(decreaseBufferPool, 50)
335+
interval = setInterval(decreaseBufferPool, 30)
328336
}
329337
}
330-
for (var i = 0; i < list.length; i++) {
338+
list[0].copy(bufferPool, pos, parser.offset, list[0].length)
339+
pos += list[0].length - parser.offset
340+
for (var i = 1; i < list.length; i++) {
331341
list[i].copy(bufferPool, pos)
332342
pos += list[i].length
333343
}
334-
return bufferPool.slice(0, length)
344+
var buffer = bufferPool.slice(bufferOffset, length + bufferOffset)
345+
bufferOffset += length
346+
return buffer
335347
}
336348

337349
/**
@@ -345,22 +357,21 @@ JavascriptRedisParser.prototype.execute = function (buffer) {
345357
this.offset = 0
346358
} else if (this.bigStrSize === 0) {
347359
var oldLength = this.buffer.length
348-
var newLength = oldLength + buffer.length
349-
// ~ 5% speed increase over using new Buffer(length) all the time
350-
if (bufferPool.length < newLength) { // We can't rely on the chunk size
351-
bufferPool = new Buffer(newLength)
352-
}
353-
this.buffer.copy(bufferPool, 0, 0, oldLength)
354-
buffer.copy(bufferPool, oldLength, 0, buffer.length)
355-
this.buffer = bufferPool.slice(0, newLength)
360+
var remainingLength = oldLength - this.offset
361+
var bufferPool = new Buffer(remainingLength + buffer.length)
362+
this.buffer.copy(bufferPool, 0, this.offset, oldLength)
363+
buffer.copy(bufferPool, remainingLength, 0, buffer.length)
364+
this.buffer = bufferPool
365+
this.offset = 0
356366
} else if (this.totalChunkSize + buffer.length >= this.bigStrSize) {
357367
this.bufferCache.push(buffer)
358368
// The returned type might be Array * (42) and in that case we can't improve the parsing currently
359-
if (this.optionReturnBuffers === false && this.buffer[0] === 36) {
369+
if (this.optionReturnBuffers === false && this.buffer[this.offset] === 36) {
360370
this.returnReply(concatBulkString(this))
361371
this.buffer = buffer
362372
} else { // This applies for arrays too
363373
this.buffer = concatBuffer(this, this.totalChunkSize + buffer.length)
374+
this.offset = 0
364375
}
365376
this.bigStrSize = 0
366377
this.totalChunkSize = 0
@@ -376,19 +387,7 @@ JavascriptRedisParser.prototype.execute = function (buffer) {
376387
var type = this.buffer[this.offset++]
377388
var response = parseType(this, type)
378389
if (response === undefined) {
379-
if (this.buffer === null) {
380-
return
381-
}
382-
var tempBuffer = new Buffer(this.buffer.length - offset)
383-
this.buffer.copy(tempBuffer, 0, offset, this.buffer.length)
384-
this.buffer = tempBuffer
385-
if (this.bigStrSize !== 0) {
386-
this.bigStrSize -= offset
387-
this.bigOffset = this.offset - offset
388-
this.totalChunkSize = this.buffer.length
389-
this.bufferCache.push(this.buffer)
390-
}
391-
this.offset = 0
390+
this.offset = offset
392391
return
393392
}
394393

test/parsers.spec.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,32 @@ describe('parsers', function () {
126126
parserOne.execute(new Buffer('tttttttttttttttttttttt\r\n'))
127127
})
128128

129+
it('returned buffers do not get mutated', function () {
130+
var replyCount = 0
131+
var results = [new Buffer('aaaaaaaaaa'), new Buffer('zzzzzzzzzz')]
132+
function checkReply (reply) {
133+
assert.deepEqual(results[replyCount], reply)
134+
results[replyCount] = reply
135+
replyCount++
136+
}
137+
var parser = new Parser({
138+
returnReply: checkReply,
139+
returnError: returnError,
140+
returnFatalError: returnFatalError,
141+
returnBuffers: true
142+
})
143+
parser.execute(new Buffer('$10\r\naaaaa'))
144+
parser.execute(new Buffer('aaaaa\r\n'))
145+
assert.strictEqual(replyCount, 1)
146+
parser.execute(new Buffer('$10\r\nzzzzz'))
147+
parser.execute(new Buffer('zzzzz\r\n'))
148+
assert.strictEqual(replyCount, 2)
149+
var str = results[0].toString()
150+
for (var i = 0; i < str.length; i++) {
151+
assert.strictEqual(str.charAt(i), 'a')
152+
}
153+
})
154+
129155
it('chunks getting to big for the bufferPool', function () {
130156
// This is a edge case. Chunks should not exceed Math.pow(2, 16) bytes
131157
var lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, ' +

0 commit comments

Comments
 (0)