Update Fix

This commit is contained in:
2026-03-15 12:30:40 +01:00
parent 311ba5e7f3
commit 50be8e25f3
176 changed files with 4075 additions and 3013 deletions

View File

@@ -406,8 +406,8 @@ class Packet {
readNullTerminatedString(encoding) {
const start = this.offset;
let end = this.offset;
while (this.buffer[end]) {
end = end + 1; // TODO: handle OOB check
while (end < this.end && this.buffer[end] !== 0x00) {
end = end + 1;
}
this.offset = end + 1;
return StringParser.decode(this.buffer, encoding, start, end);
@@ -516,16 +516,20 @@ class Packet {
return result * sign;
}
// copy-paste from https://github.com/mysqljs/mysql/blob/master/lib/protocol/Parser.js
// adapted from https://github.com/mysqljs/mysql/blob/dc9c152a87ec51a1f647447268917243d2eab1fd/lib/protocol/Parser.js
parseGeometryValue() {
const buffer = this.readLengthCodedBuffer();
let offset = 4;
if (buffer === null || !buffer.length) {
return null;
}
const bufferLength = buffer.length;
function parseGeometry() {
let x, y, i, j, numPoints, line;
let x, y, i, j, numPoints, numRings, num, line;
let result = null;
if (offset + 5 > bufferLength) {
return null;
}
const byteOrder = buffer.readUInt8(offset);
offset += 1;
const wkbType = byteOrder
@@ -534,6 +538,9 @@ class Packet {
offset += 4;
switch (wkbType) {
case 1: // WKBPoint
if (offset + 16 > bufferLength) {
return null;
}
x = byteOrder
? buffer.readDoubleLE(offset)
: buffer.readDoubleBE(offset);
@@ -545,12 +552,21 @@ class Packet {
result = { x: x, y: y };
break;
case 2: // WKBLineString
if (offset + 4 > bufferLength) {
return null;
}
numPoints = byteOrder
? buffer.readUInt32LE(offset)
: buffer.readUInt32BE(offset);
offset += 4;
if (numPoints > (bufferLength - offset) / 16) {
return null;
}
result = [];
for (i = numPoints; i > 0; i--) {
if (offset + 16 > bufferLength) {
break;
}
x = byteOrder
? buffer.readDoubleLE(offset)
: buffer.readDoubleBE(offset);
@@ -563,19 +579,30 @@ class Packet {
}
break;
case 3: // WKBPolygon
// eslint-disable-next-line no-case-declarations
const numRings = byteOrder
if (offset + 4 > bufferLength) {
return null;
}
numRings = byteOrder
? buffer.readUInt32LE(offset)
: buffer.readUInt32BE(offset);
offset += 4;
if (numRings > (bufferLength - offset) / 4) {
return null;
}
result = [];
for (i = numRings; i > 0; i--) {
if (offset + 4 > bufferLength) {
break;
}
numPoints = byteOrder
? buffer.readUInt32LE(offset)
: buffer.readUInt32BE(offset);
offset += 4;
line = [];
for (j = numPoints; j > 0; j--) {
if (offset + 16 > bufferLength) {
break;
}
x = byteOrder
? buffer.readDoubleLE(offset)
: buffer.readDoubleBE(offset);
@@ -593,11 +620,16 @@ class Packet {
case 5: // WKBMultiLineString
case 6: // WKBMultiPolygon
case 7: // WKBGeometryCollection
// eslint-disable-next-line no-case-declarations
const num = byteOrder
if (offset + 4 > bufferLength) {
return null;
}
num = byteOrder
? buffer.readUInt32LE(offset)
: buffer.readUInt32BE(offset);
offset += 4;
if (num > (bufferLength - offset) / 9) {
return null;
}
result = [];
for (i = num; i > 0; i--) {
result.push(parseGeometry());
@@ -660,14 +692,27 @@ class Packet {
if (len === null) {
return null;
}
if (len === 0) {
return 0; // TODO: assert? exception?
}
// For numbers with many digits (>17), use built-in parseFloat to avoid
// precision loss from accumulated rounding errors in repeated *10 operations.
// This fixes issues #2928 (MAX_VALUE doubles) and #3690 (DECIMAL(36,18))
// where very large numbers or numbers with many fractional digits lose precision.
// The threshold of 17 is based on IEEE 754 double precision (~15-17 significant digits).
// Testing shows minimal performance impact as most real-world numbers are shorter.
if (len > 17) {
const str = this.buffer.toString('utf8', this.offset, this.offset + len);
this.offset += len;
return Number.parseFloat(str);
}
let result = 0;
const end = this.offset + len;
let factor = 1;
let pastDot = false;
let charCode = 0;
if (len === 0) {
return 0; // TODO: assert? exception?
}
if (this.buffer[this.offset] === minus) {
this.offset++;
factor = -1;
@@ -681,9 +726,13 @@ class Packet {
pastDot = true;
this.offset++;
} else if (charCode === exponent || charCode === exponentCapital) {
this.offset++;
const exponentValue = this.parseInt(end - this.offset);
return (result / factor) * Math.pow(10, exponentValue);
// Scientific notation detected - bail out to parseFloat for exact match.
// Manual calculation with Math.pow(10, exp) cannot match parseFloat()
// exactly for most non-zero exponents due to accumulated rounding errors.
const start = end - len;
const str = this.buffer.toString('utf8', start, end);
this.offset = end;
return Number.parseFloat(str);
} else {
result *= 10;
result += this.buffer[this.offset] - 48;
@@ -831,11 +880,10 @@ class Packet {
if (n === null) {
return this.writeInt8(0xfb);
}
// TODO: check that n is out of int precision
this.writeInt8(0xfe);
this.buffer.writeUInt32LE(n, this.offset);
this.buffer.writeUInt32LE(n >>> 0, this.offset);
this.offset += 4;
this.buffer.writeUInt32LE(n >> 32, this.offset);
this.buffer.writeUInt32LE(Math.floor(n / 0x100000000), this.offset);
this.offset += 4;
return this.offset;
}