{"record":{"id":"925256557661c0b3","repo":"apache/flink","slug":"this-memory-segment-has-been-freed","errorCode":null,"errorMessage":"this memory segment has been freed.","messagePattern":"this memory segment has been freed\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"flink-core/src/main/java/org/apache/flink/core/memory/MemorySegment.java","lineNumber":1588,"sourceCode":"            byte[] tempBuffer, MemorySegment seg2, int offset1, int offset2, int len) {\n        if ((offset1 | offset2 | len | (tempBuffer.length - len)) >= 0) {\n            final long thisPos = this.address + offset1;\n            final long otherPos = seg2.address + offset2;\n\n            if (thisPos <= this.addressLimit - len && otherPos <= seg2.addressLimit - len) {\n                // this -> temp buffer\n                UNSAFE.copyMemory(\n                        this.heapMemory, thisPos, tempBuffer, BYTE_ARRAY_BASE_OFFSET, len);\n\n                // other -> this\n                UNSAFE.copyMemory(seg2.heapMemory, otherPos, this.heapMemory, thisPos, len);\n\n                // temp buffer -> other\n                UNSAFE.copyMemory(\n                        tempBuffer, BYTE_ARRAY_BASE_OFFSET, seg2.heapMemory, otherPos, len);\n                return;\n            } else if (this.address > this.addressLimit) {\n                throw new IllegalStateException(\"this memory segment has been freed.\");\n            } else if (seg2.address > seg2.addressLimit) {\n                throw new IllegalStateException(\"other memory segment has been freed.\");\n            }\n        }\n\n        // index is in fact invalid\n        throw new IndexOutOfBoundsException(\n                String.format(\n                        \"offset1=%d, offset2=%d, len=%d, bufferSize=%d, address1=%d, address2=%d\",\n                        offset1, offset2, len, tempBuffer.length, this.address, seg2.address));\n    }\n\n    /**\n     * Equals two memory segment regions.\n     *\n     * @param seg2 Segment to equal this segment with\n     * @param offset1 Offset of this segment to start equaling\n     * @param offset2 Offset of seg2 to start equaling","sourceCodeStart":1570,"sourceCodeEnd":1606,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/core/memory/MemorySegment.java#L1570-L1606","documentation":"MemorySegment.swapBytes(seg2, tempBuffer, offset1, offset2, len) swaps two memory regions via a temp buffer. After the bounds check fails it checks liveness: if this segment was already freed (address > addressLimit) it throws IllegalStateException('this memory segment has been freed.') — the error identifies the receiver ('this'), not the argument.","triggerScenarios":"Calling swapBytes where the receiving segment has been freed — e.g. in sort/merge code that keeps operating on segments already returned to the memory manager after a spill or cancellation.","commonSituations":"External sorters reordering buffers after a failed check released them; task cancellation paths that free segments while a sort thread is still swapping; segment pool returned early on exception.","solutions":["Check this.isFreed() before swapping and abort the sort/spill operation.","Fix the lifecycle: do not return segments to the pool until all sort/merge threads using them have completed (drain threads before releasing).","If the other segment is the freed one you will see the sibling message 'other memory segment has been freed.' — use the message to tell which side to fix."],"exampleFix":"// before\na.swapBytes(b, tempBuf, off1, off2, len); // 'this ... has been freed.' => a is freed\n\n// after\nif (a.isFreed() || b.isFreed()) {\n    throw new IllegalStateException(\"cannot swap: segment already released\");\n}\na.swapBytes(b, tempBuf, off1, off2, len);","handlingStrategy":"validation","validationCode":"if (seg1.isFreed() || seg2.isFreed()) {\n    throw new IllegalStateException(\"cannot swap: a segment was already freed\");\n}\nseg1.swapBytes(seg2, tempBuf, off1, off2, len);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["'this ... has been freed.' names the receiver; 'other ...' names the argument — read the message to find the culprit.","Do not return sort-buffer segments to the pool while sort/merge threads may still swap them."],"tags":["memory","lifecycle","flink-core","use-after-free"],"backgroundTag":null,"analyzedSha":"2f3c205e9266cb30240eb7f4fdab15cad629a70f","analyzedAt":"2026-08-14T08:48:24.518Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}