{"record":{"id":"85788259cdc8e5ba","repo":"apache/flink","slug":"segment-has-been-freed","errorCode":null,"errorMessage":"segment has been freed","messagePattern":"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":344,"sourceCode":"        return wrapInternal(offset, length);\n    }\n\n    private ByteBuffer wrapInternal(int offset, int length) {\n        if (address <= addressLimit) {\n            if (heapMemory != null) {\n                return ByteBuffer.wrap(heapMemory, offset, length);\n            } else {\n                try {\n                    ByteBuffer wrapper = Preconditions.checkNotNull(offHeapBuffer).duplicate();\n                    wrapper.limit(offset + length);\n                    wrapper.position(offset);\n                    return wrapper;\n                } catch (IllegalArgumentException e) {\n                    throw new IndexOutOfBoundsException();\n                }\n            }\n        } else {\n            throw new IllegalStateException(\"segment has been freed\");\n        }\n    }\n\n    /**\n     * Gets the owner of this memory segment. Returns null, if the owner was not set.\n     *\n     * @return The owner of the memory segment, or null, if it does not have an owner.\n     */\n    @Nullable\n    public Object getOwner() {\n        return owner;\n    }\n\n    // ------------------------------------------------------------------------\n    //                    Random Access get() and put() methods\n    // ------------------------------------------------------------------------\n\n    // ------------------------------------------------------------------------","sourceCodeStart":326,"sourceCodeEnd":362,"githubUrl":"https://github.com/apache/flink/blob/2f3c205e9266cb30240eb7f4fdab15cad629a70f/flink-core/src/main/java/org/apache/flink/core/memory/MemorySegment.java#L326-L362","documentation":"Inside wrapInternal, a segment is detected as freed when address > addressLimit (free() deliberately sets address = addressLimit + 1 to poison it). Calling wrap(offset, length) on a freed segment therefore throws IllegalStateException('segment has been freed') before any ByteBuffer can be created.","triggerScenarios":"Calling wrap() after MemorySegment.free() (or after the owning pool recycled the segment), e.g. retaining a ByteBuffer view beyond the segment's lifetime, or wrapping a buffer that a failed task already released.","commonSituations":"Caching wrapped ByteBuffers past buffer recycle points in network-stack or sink code; error paths that free segments while other components still hold references; asynchronous writers using a view of memory already returned to the pool.","solutions":["Check segment.isFreed() before wrapping and abort/skip if freed.","Fix ownership so nothing touches a segment after free()/recycle — release cached views before recycling the buffer.","If a ByteBuffer must outlive the segment, copy the bytes into an owned buffer before the segment is freed."],"exampleFix":"// before\nByteBuffer view = segment.wrap(offset, length); // IllegalStateException after free()\n\n// after\nif (segment.isFreed()) {\n    throw new IllegalStateException(\"buffer already recycled; copy earlier\");\n}\nByteBuffer view = segment.wrap(offset, length);","handlingStrategy":"validation","validationCode":"if (segment.isFreed()) {\n    throw new IllegalStateException(\"segment already freed; cannot wrap\");\n}\nByteBuffer view = segment.wrap(offset, length);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hold a wrapped ByteBuffer past the segment's lifetime — copy if the view must survive.","Check isFreed() at every wrap site that can race a recycle path."],"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"}