@@ -54,12 +54,11 @@ Also fixed in the same pass:
5454 never reset after the first ` writeName ` , making every subsequent ` writeName ` return
5555 false.
5656
57- Note: ` messageBufferOutputHolder ` ThreadLocal was NOT fixed here — calling
58- ` messageBufferOutputHolder.remove() ` in ` _releaseBuffers() ` caused a 23% serialization
59- regression by defeating the ThreadLocal caching (each close allocates a new
60- ` OutputStreamBufferOutput ` on the next generator creation). Dropped in favour of
61- accepting the minor OutputStream retention, which is only observable when a thread
62- creates exactly one generator and never creates another.
57+ Note: ` messageBufferOutputHolder ` ThreadLocal OutputStream retention — FIXED (see
58+ preexisting-issues section 4 below). ` messageBufferOutputHolder.remove() ` caused a 23%
59+ regression; instead ` _releaseBuffers() ` now calls ` messageBufferOutput.reset(null) ` to
60+ release the OutputStream reference while keeping the ` OutputStreamBufferOutput ` object
61+ alive for reuse.
6362
6463### 5. ` writeString(Reader, int) ` len≥0 path allocates unbounded buffer — FIXED
6564
@@ -143,12 +142,27 @@ identically in msgpack-jackson. They should be addressed in both modules togethe
143142
144143## 1. ` MessagePackParser ` : Same byte-array input skips unpacker reset
145144
146- ** File:** ` msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java:130 `
145+ ** Files:**
146+ - ` msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java:130 `
147+ - ` msgpack-jackson3/src/main/java/org/msgpack/jackson/dataformat/MessagePackParser.java:108 ` — FIXED
148+
149+ When ` AUTO_CLOSE_SOURCE ` is disabled and the same ` byte[] ` instance is parsed more
150+ than once, the condition ` messageUnpackerTuple.first() != src ` is false, so the unpacker
151+ is not reset. The second parse continues from where the first left off (typically EOF)
152+ instead of from the beginning.
153+
154+ Bug only manifests when all three conditions hold: (1) ` reuseResourceInParser=true ` ,
155+ (2) ` AUTO_CLOSE_SOURCE ` disabled (non-default), (3) the same ` byte[] ` reference reused.
156+
157+ ** Note on msgpack-jackson3:** In practice, issue #2 's fix (clearing the ` byte[] ` from the
158+ ThreadLocal on ` close() ` ) incidentally prevents this bug from manifesting — after close,
159+ the cached src becomes ` null ` , so the next parse always sees ` null != bytes ` and resets.
160+ Fixed explicitly anyway (` || src instanceof byte[] ` ) to make intent clear and remove the
161+ subtle dependency between the two fixes. Regression test:
162+ ` MessagePackParserTest.testByteArrayReuseResetsUnpackerWhenAutoCloseSourceDisabled ` .
147163
148- When ` AUTO_CLOSE_SOURCE ` is disabled and the same byte-array instance is parsed more
149- than once (e.g. reused buffer), the condition ` messageUnpackerTuple.first() != src `
150- is false, so the unpacker is not reset. The second parse continues from where the first
151- left off instead of from the beginning.
164+ Needs the same explicit fix in msgpack-jackson (where issue #2 is also not yet fixed, so
165+ both bugs compound).
152166
153167## 2. ` MessagePackParser ` : ThreadLocal retains last byte-array payload per thread
154168
@@ -259,3 +273,35 @@ Fixed in msgpack-jackson3 using `bb.arrayOffset() + bb.position()`; needs the sa
259273with a ` ByteBuffer ` field that was sliced or partially consumed will silently produce
260274corrupt serialized output. No exception is thrown.
261275
276+ ## 11. ` MessagePackFactory ` : byte-array parser copies the input slice unnecessarily
277+
278+ ** Files:**
279+ - ` msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java:143 `
280+ - ` msgpack-jackson3/src/main/java/org/msgpack/jackson/dataformat/MessagePackFactory.java ` — FIXED
281+
282+ ` _createParser(byte[], int, int) ` calls ` Arrays.copyOfRange(data, offset, offset + len) ` to
283+ extract the slice, then wraps the copy in ` InputStreamBufferInput ` . ` ArrayBufferInput ` already
284+ accepts ` (data, offset, len) ` directly and avoids the copy entirely.
285+ Fixed in msgpack-jackson3 by constructing ` ArrayBufferInput(data, offset, len) ` and passing it
286+ to the ` MessageBufferInput ` -taking constructor; needs the same fix in msgpack-jackson.
287+
288+ ** Practical impact:** Low for small payloads; proportional to payload size for large messages
289+ since the entire slice is copied on every ` readValue ` call.
290+
291+ ## 12. ` MessagePackGenerator ` : non-array-backed ByteBuffer read advances caller's position
292+
293+ ** Files:**
294+ - ` msgpack-jackson/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java:373 `
295+ - ` msgpack-jackson3/src/main/java/org/msgpack/jackson/dataformat/MessagePackGenerator.java ` — FIXED
296+
297+ When serializing a ` ByteBuffer ` whose ` hasArray() ` is false (e.g. direct buffers), the
298+ generator calls ` bb.get(data) ` which advances the buffer's position as a side effect. The
299+ ` hasArray() ` fast path is non-destructive (`writePayload(bb.array(), bb.arrayOffset() +
300+ bb.position(), len)`), so the two paths are inconsistent.
301+ Fixed in msgpack-jackson3 using ` bb.duplicate().get(data) ` — ` duplicate() ` shares the
302+ backing store without copying data (O(1)) but has its own independent position.
303+ Needs the same fix in msgpack-jackson.
304+
305+ ** Practical impact:** Low. Direct ByteBuffers are uncommon in typical POJO fields, and the
306+ mutation is only observable if the caller inspects or reuses the buffer after serialization.
307+
0 commit comments