{"record":{"id":"252b09375668799c","repo":"MuntashirAkon/AppManager","slug":"direct-buffer-somehow-written-to-bufferatatimeoutputchannel","errorCode":null,"errorMessage":"Direct buffer somehow written to BufferAtATimeOutputChannel","messagePattern":"Direct buffer somehow written to BufferAtATimeOutputChannel","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/org/apache/commons/compress/utils/FixedLengthBlockOutputStream.java","lineNumber":223,"sourceCode":"     * breaks up writes into 8KB max chunks. Since the purpose of this class is to always write\n     * complete blocks, we need to write a simple class to take care of it.\n     */\n    private static class BufferAtATimeOutputChannel implements WritableByteChannel {\n\n        private final OutputStream out;\n        private final AtomicBoolean closed = new AtomicBoolean(false);\n\n        private BufferAtATimeOutputChannel(final OutputStream out) {\n            this.out = out;\n        }\n\n        @Override\n        public int write(final ByteBuffer buffer) throws IOException {\n            if (!isOpen()) {\n                throw new ClosedChannelException();\n            }\n            if (!buffer.hasArray()) {\n                throw new IOException(\"Direct buffer somehow written to BufferAtATimeOutputChannel\");\n            }\n\n            try {\n                final int pos = buffer.position();\n                final int len = buffer.limit() - pos;\n                out.write(buffer.array(), buffer.arrayOffset() + pos, len);\n                buffer.position(buffer.limit());\n                return len;\n            } catch (final IOException e) {\n                try {\n                    close();\n                } catch (final IOException ignored) { //NOSONAR\n                }\n                throw e;\n            }\n        }\n\n        @Override","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/org/apache/commons/compress/utils/FixedLengthBlockOutputStream.java#L205-L241","documentation":"The BufferAtATimeOutputChannel inner class of FixedLengthBlockOutputStream only supports heap-backed ByteBuffers: it copies via buffer.array(). Direct (off-heap) buffers have no accessible array, so writing one throws this IOException as an internal contract violation.","triggerScenarios":"Calling write(ByteBuffer) on BufferAtATimeOutputChannel with a direct ByteBuffer allocated via ByteBuffer.allocateDirect(...) (e.g. obtained from NIO pooling or JNI code).","commonSituations":"Passing pooled direct buffers from network code into the block stream; assuming all ByteBuffers are array-backed; refactoring code from heap to direct buffers for performance.","solutions":["Wrap the direct buffer's contents into a heap buffer first (allocate a heap buffer, put the direct buffer's remaining bytes, then write)","Use ByteBuffer.allocate() instead of allocateDirect() for buffers destined for this stream","Copy data to a byte[] and use the array-based write"],"exampleFix":"// before\nchannel.write(directBuffer); // IOException: buffer.hasArray() == false\n// after\nByteBuffer heap = ByteBuffer.allocate(directBuffer.remaining());\nheap.put(directBuffer.duplicate());\nheap.flip();\nchannel.write(heap);","handlingStrategy":"type-guard","validationCode":"if (!buffer.isDirect() && buffer.hasArray()) { channel.write(buffer); } else { /* copy to heap buffer first */ }","typeGuard":"boolean isWritableByBufferAtATime(ByteBuffer b) { return b != null && !b.isDirect() && b.hasArray(); }","tryCatchPattern":"try { channel.write(buffer); } catch (IOException e) { if (e.getMessage().contains(\"Direct buffer\")) { ByteBuffer heap = ByteBuffer.allocate(buffer.remaining()); heap.put(buffer.duplicate()).flip(); channel.write(heap); } else throw e; }","preventionTips":["Only pass heap ByteBuffers (ByteBuffer.allocate) to this channel","Copy direct buffers into heap buffers before writing","Watch for pooled/borrowed direct buffers from NIO/JNI layers"],"tags":["nio","bytebuffer","io"],"backgroundTag":"incompatible-source-type","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}