[
https://issues.apache.org/jira/browse/GEODE-10521?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Jinwoo Hwang updated GEODE-10521:
---------------------------------
Description:
h2. Problem Description
h3. Current State
The {{AddressableMemoryManager}} class in {{geode-core}} currently uses
reflection to access private internal APIs of {{{}java.nio.DirectByteBuffer{}}}:
# {{DirectByteBuffer.address()}} method - to retrieve the native memory
address from a DirectByteBuffer
# {{DirectByteBuffer(long, int)}} constructor - to create a DirectByteBuffer
wrapping a native memory address
This reflection-based approach requires calling {{setAccessible(true)}} on both
the method and constructor, which violates Java's module encapsulation rules
introduced in Java 9 (JEP 260, 261).
h3. Required JVM Flag
To allow this reflection at runtime, Apache Geode currently requires the
following JVM flag:
{code:java}
--add-opens=java.base/java.nio=ALL-UNNAMED
{code}
This flag is hardcoded in {{MemberJvmOptions.JAVA_11_OPTIONS}} as
{{JAVA_NIO_OPEN}} and automatically added to all Geode member JVMs running on
Java 11 and later.
h3. Code Evidence
Current implementation in {{{}AddressableMemoryManager.java{}}}:
{code:java}
// Reflection-based access requiring --add-opens
private static volatile Method dbbAddressMethod = null;
private static volatile Constructor dbbCtor = null;
public static long getDirectByteBufferAddress(ByteBuffer bb) {
Method m = dbbAddressMethod;
if (m == null) {
m = dbbClass.getDeclaredMethod("address");
m.setAccessible(true); // REQUIRES --add-opens
dbbAddressMethod = m;
}
return (Long) m.invoke(bb);
}
static ByteBuffer createDirectByteBuffer(long address, int size) {
Constructor ctor = dbbCtor;
if (ctor == null) {
ctor = dbbClass.getDeclaredConstructor(long.class, int.class);
ctor.setAccessible(true); // REQUIRES --add-opens
dbbCtor = ctor;
}
return (ByteBuffer) ctor.newInstance(address, size);
}
{code}
h2. Business Impact
h3. Security and Compliance Issues
h4. Java Platform Security Model Violations
The use of {{--add-opens}} flags represents a security concern and technical
debt:
* {*}Strong Encapsulation Bypass{*}: The flag explicitly breaks Java's module
system encapsulation, which was designed to protect internal implementation
details
* {*}Security Manager Conflicts{*}: In environments with security managers or
restricted permissions, these flags may be blocked or flagged as security
violations
* {*}Audit Trail Issues{*}: Security audits and compliance scans flag
{{--add-opens}} usage as potential vulnerabilities
* {*}Attack Surface{*}: Opening internal packages to ALL-UNNAMED increases the
attack surface by allowing any code to access these internals
h4. Deployment and Operations Impact
The required JVM flag creates operational friction:
* {*}Container Security Policies{*}: Many container platforms (Kubernetes,
Docker Enterprise) have security policies that restrict or audit JVM flags
* {*}Cloud Platform Restrictions{*}: Some cloud platforms (AWS Lambda, Azure
Functions, GCP Cloud Run) restrict or monitor JVM flags
* {*}Enterprise Security Policies{*}: Enterprise security teams often require
justification and approval for {{--add-opens}} flags
* {*}Deployment Complexity{*}: Administrators must remember to include the
flag in all deployment configurations
h4. Forward Compatibility Risk
Java's module system evolution poses risks:
* {*}JEP 403 (Java 17+){*}: Strongly encapsulates JDK internals by default,
with warnings issued for illegal reflective access
* {*}Future Java Versions{*}: The Java platform is moving toward stricter
enforcement of module boundaries
* {*}Deprecation Path{*}: {{--add-opens}} may become deprecated or restricted
in future Java releases
* {*}Migration Cost{*}: The longer this technical debt remains, the more
costly it becomes to remediate
h3. Technical Impact
h4. Off-Heap Memory Management
{{AddressableMemoryManager}} is a critical component in Geode's off-heap memory
management:
* {*}Purpose{*}: Manages direct ByteBuffer access to off-heap memory regions
* {*}Performance Critical{*}: Used in hot paths for off-heap data access
* {*}Memory Safety{*}: Provides abstraction layer over native memory addresses
* {*}Zero-Copy Operations{*}: Enables wrapping native memory addresses as
ByteBuffers without copying data
Current usage patterns:
{code:java}
// Get address from a DirectByteBuffer
long address = AddressableMemoryManager.getDirectByteBufferAddress(buffer);
// Create a ByteBuffer wrapping a native memory address
ByteBuffer wrapper = AddressableMemoryManager.createDirectByteBuffer(address,
size);
{code}
h4. Dependency Chain
The {{java.nio}} module opening affects multiple components:
* {{{}geode-core{}}}: Direct usage in {{AddressableMemoryManager}}
* {{{}geode-gfsh{}}}: Automatic flag injection via {{MemberJvmOptions}}
* All Geode members: Every server, locator, and client requires the flag
* Test infrastructure: All integration and unit tests must include the flag
h2. Benefits of Remediation
h3. Security and Compliance
* {*}Eliminates Security Audit Findings{*}: Removes {{--add-opens}} flag from
security scan results
* {*}Improves Security Posture{*}: Operates within Java's intended security
model
* {*}Simplifies Compliance{*}: Reduces justification burden for security teams
* {*}Future-Proof Security{*}: Aligns with Java platform security evolution
h3. Operational Excellence
* {*}Simplified Deployment{*}: One less JVM flag to configure and document
* {*}Cloud-Native Friendly{*}: Compatible with restrictive cloud platform
policies
* {*}Container Security{*}: Passes stricter container security policies
without exceptions
* {*}Reduced Configuration Complexity{*}: Fewer deployment-specific
configurations to maintain
h3. Java Platform Compatibility
* {*}Java 17+ Ready{*}: Fully compatible with JEP 403 strong encapsulation
* {*}Java 21 Forward Compatible{*}: No deprecation warnings or compatibility
issues
* {*}Virtual Threads Compatible{*}: Works correctly with Project Loom virtual
threads
* {*}GraalVM Native Image Ready{*}: Eliminates reflection that complicates
native image generation
h3. Developer Experience
* {*}Cleaner Code{*}: Less reflection boilerplate and error handling
* {*}Better IDE Support{*}: IDEs can analyze code without reflection
indirection
* {*}Easier Testing{*}: Tests don't require special JVM flag configurations
* {*}Reduced Maintenance{*}: Eliminates reflection-related failure modes
h3. Performance Considerations
* {*}Faster Reflection{*}: Field offset caching is more efficient than method
reflection
* {*}JIT Optimization{*}: Direct Unsafe field access optimizes better than
reflective method invocation
* {*}Reduced Overhead{*}: Eliminates {{invoke()}} overhead on every call
* {*}Better Inlining{*}: JIT compiler can inline field access more
aggressively than reflection
h2. Module System Context
This issue is part of a broader initiative to eliminate all JVM module system
violations in Apache Geode:
h3. Related Work
* {*}GEODE-10519{*}: Eliminated
{{--add-opens=java.base/java.lang=ALL-UNNAMED}} ({{{}UnsafeThreadLocal{}}})
* {*}GEODE-10520{*}: Eliminated
{{--add-exports=java.base/sun.nio.ch=ALL-UNNAMED}} ({{{}DirectBuffer{}}})
* {*}GEODE-10521{*}: This issue - Eliminate
{{--add-opens=java.base/java.nio=ALL-UNNAMED}}
({{{}AddressableMemoryManager{}}})
* {*}Future{*}:
{{--add-opens=java.base/com.sun.management.internal=ALL-UNNAMED}}
({{{}VMStats50{}}})
h3. Strategic Goal
The ultimate goal is to run Apache Geode on Java 17, and 21 without requiring
any {{-{-}add-opens{-}}} or {{-add-exports}} flags, ensuring:
* Full compliance with Java module system
* Maximum security and encapsulation
* Forward compatibility with future Java releases
* Cloud-native and container-friendly deployment
h2. Affected Versions
* All Geode versions running on Java 17 and later
* Particularly impacts Java 17+ deployments where strong encapsulation
warnings appear
h2. References
* [JEP 260: Encapsulate Most Internal APIs|https://openjdk.org/jeps/260]
* [JEP 261: Module System|https://openjdk.org/jeps/261]
* [JEP 403: Strongly Encapsulate JDK Internals|https://openjdk.org/jeps/403]
* Java Platform Module System (JPMS) specification
h2. Additional Context
h3. Why Reflection Was Used Initially
The original implementation used reflection because:
# {{DirectByteBuffer}} constructor is package-private (not accessible)
# {{DirectByteBuffer.address()}} method is package-private (not accessible)
# Public {{ByteBuffer}} API doesn't expose native memory address
# No public API exists to wrap an arbitrary memory address as a ByteBuffer
This was a pragmatic solution when Java 9 was new and the module system
implications were less understood.
h3. Off-Heap Memory Architecture
Geode's off-heap memory management is critical for large heap scenarios:
* Reduces garbage collection pressure by keeping data off-heap
* Enables multi-gigabyte caches without GC pauses
* Provides direct memory access for serialization/deserialization
* Supports memory-mapped file operations
{{AddressableMemoryManager}} is a cornerstone of this architecture, making its
security and compatibility critical.
was:
h2. Summary
Apache Geode currently accesses the internal {{sun.nio.ch.DirectBuffer}}
interface to track buffer slice-to-original mappings in {{{}BufferPool{}}}.
This requires the JVM export flag
{{{}--add-exports=java.base/sun.nio.ch=ALL-UNNAMED{}}}, creating security
vulnerabilities, operational complexity, and maintenance risks. This access
violates Java Platform Module System (JPMS) encapsulation and depends on
non-public APIs that could change or be removed in future JDK releases.
h2. Problem Description
h3. Current Implementation Dependencies
The {{BufferPool}} class in
{{geode-core/src/main/java/org/apache/geode/internal/tcp/Connection.java}}
manages ByteBuffer pooling for network communication. When creating buffer
slices, it needs to track the relationship between slices and their original
buffers to support proper buffer pooling and reuse.
*Current approach:*
* Uses {{sun.nio.ch.DirectBuffer}} internal interface
* Calls {{DirectBuffer.attachment()}} method to retrieve the original buffer
from a slice
* Requires a wrapper class in {{geode-unsafe}} module to access this internal
API
* Necessitates JVM export flag:
{{--add-exports=java.base/sun.nio.ch=ALL-UNNAMED}}
*Code location:*
{{geode-core/src/main/java/org/apache/geode/internal/tcp/Connection.java}}
{code:java}
// Current implementation accessing internal API
import org.apache.geode.unsafe.internal.sun.nio.ch.DirectBuffer;
// In BufferPool class
DirectBuffer directBuffer = (DirectBuffer) buffer;
ByteBuffer attachment = (ByteBuffer) directBuffer.attachment();
{code}
h3. Required JVM Configuration
To enable this internal API access, Geode requires the following JVM export
flag (defined in {{{}MemberJvmOptions.java{}}}):
{code:java}
/**
* export needed by DirectBuffer wrapper
*/
private static final String SUN_NIO_CH_EXPORT =
"--add-exports=java.base/sun.nio.ch=ALL-UNNAMED";
{code}
This flag must be configured on all Geode server JVMs, adding to the
operational burden alongside other required flags for {{java.lang}} and
{{java.nio}} access.
h3. Wrapper Module Requirements
The {{geode-unsafe}} module contains a wrapper class to access the internal
DirectBuffer interface:
{{geode-unsafe/src/main/java/org/apache/geode/unsafe/internal/sun/nio/ch/DirectBuffer.java}}
This wrapper:
* Duplicates the internal interface definition
* Creates tight coupling to JDK internals
* Requires maintenance when JDK internal structures change
* Adds complexity to the build and dependency management
h2. Problems with Current Approach
h3. 1. Java Module System Violations
*Severity: High*
The current approach directly violates the Java Platform Module System (JPMS)
encapsulation:
* Accesses internal implementation details of {{sun.nio.ch}} package
* Bypasses the module system's access controls
* Requires explicit {{--add-exports}} directive to override module boundaries
* Opens entire {{sun.nio.ch}} package to all unnamed modules
{*}Risk{*}: Future Java versions may further restrict or remove the ability to
export internal packages, even with command-line flags. The {{sun.*}} packages
are explicitly documented as internal and subject to change without notice.
h3. 2. Maintenance Burden and Fragility
*Severity: High*
The implementation is brittle and creates ongoing maintenance costs:
* Internal interface definitions may change between JDK releases
* Method signatures in {{sun.nio.ch.DirectBuffer}} could be modified
* The {{attachment()}} mechanism could be removed or redesigned
* Wrapper class must be manually synchronized with JDK changes
* No compiler warnings when internal APIs change
{*}Historical precedent{*}: Oracle has removed or modified internal APIs in
past JDK releases, breaking code that depended on them. The {{sun.*}} namespace
carries no stability guarantees.
h3. 3. Security Concerns
*Severity: Medium-High*
Using {{{}--add-exports=java.base/sun.nio.ch=ALL-UNNAMED{}}}:
* Opens internal NIO channel implementation to all unnamed modules
* Grants broader access than necessary (only need buffer attachment tracking)
* Weakens Java's security model and module encapsulation
* May trigger security audit flags in enterprise environments
* Creates potential attack vectors by exposing internal implementation
{*}Security implications{*}:
* Internal {{sun.nio.ch}} classes handle low-level I/O operations
* Exposing these internals could enable manipulation of channel state
* Buffer management internals could be exploited if exposed
* Violates principle of least privilege
h3. 4. Operational Complexity
*Severity: Medium*
Current deployment requirements:
* JVM export flags must be correctly configured on all Geode servers
* Different flag configurations needed for different Java versions
* Documentation and deployment scripts must track required flags
* Missing flags cause runtime failures with cryptic error messages
* Troubleshooting is complicated by module system violations
>From {{{}MemberJvmOptions.java{}}}, the growing list of required flags:
{code:java}
static final List<String> JAVA_11_OPTIONS = Arrays.asList(
COM_SUN_JMX_REMOTE_SECURITY_EXPORT,
SUN_NIO_CH_EXPORT, // ← Required for DirectBuffer access
COM_SUN_MANAGEMENT_INTERNAL_OPEN,
JAVA_LANG_OPEN,
JAVA_NIO_OPEN);
{code}
Each additional flag increases:
* Configuration complexity
* Risk of misconfiguration
* Deployment documentation burden
* Operational support costs
h3. 5. Build and Dependency Complexity
*Severity: Low-Medium*
The {{geode-unsafe}} module approach:
* Adds extra module to build and maintain
* Creates circular dependency concerns
* Complicates IDE setup and development workflow
* Increases build time and complexity
* Requires special handling in build tools
h3. 6. Compliance and Audit Issues
*Severity: Medium*
Enterprise environments face challenges:
* Security audits flag usage of internal APIs
* Compliance reviews require justification for module violations
* Risk assessment must account for non-public API dependencies
* Change management processes are triggered by JDK upgrades
* Documentation burden for security exception approvals
h2. Business Impact
h3. Reduced Security Risk
Eliminating {{sun.nio.ch}} access:
* Removes need to export internal NIO channel implementation
* Reduces attack surface by not exposing low-level I/O internals
* Simplifies security audits and compliance reviews
* Follows principle of least privilege
* Eliminates security exception requirements
h3. Improved Operational Simplicity
Removing the JVM export flag requirement:
* Simplifies deployment procedures
* Reduces configuration errors in production
* Removes a potential point of failure during Java upgrades
* Improves compatibility with container orchestration platforms
* Reduces operational support burden
h3. Better Java Version Compatibility
A solution using only public APIs:
* Works seamlessly across all Java versions (17, 21+)
* Doesn't depend on JDK internal implementation details
* Reduces risk during major Java version upgrades
* Aligns with Java's "code to interfaces, not implementations" principle
* Protects against breaking changes in future JDKs
h3. Enhanced Long-Term Maintainability
Moving away from internal APIs:
* Eliminates the {{geode-unsafe}} wrapper module
* Reduces technical debt significantly
* Makes the codebase more sustainable
* Demonstrates modern Java best practices
* Simplifies onboarding for new contributors
h3. Reduced Build Complexity
Removing {{geode-unsafe}} module:
* Simplifies build configuration
* Reduces module interdependencies
* Improves IDE development experience
* Faster build times
* Cleaner dependency graph
h2. Scope
h3. Affected Components
*Source Files*
* {{geode-core/src/main/java/org/apache/geode/internal/tcp/Connection.java}} -
BufferPool class (primary)
*
{{geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/MemberJvmOptions.java}}
- JVM flags
*
{{geode-unsafe/src/main/java/org/apache/geode/unsafe/internal/sun/nio/ch/DirectBuffer.java}}
- Wrapper (to be removed)
*Test Files*
* {{geode-core/src/test/java/.../BufferPoolTest.java}} - Buffer pooling tests
* {{geode-unsafe/src/test/java/.../DirectBufferTest.java}} - Wrapper tests (to
be removed)
h3. Scope
* Analysis of buffer slice-to-original mapping requirements
* Evaluation of public API alternatives (WeakHashMap, custom tracking)
* Assessment of memory management implications
* Performance impact analysis
* Compatibility evaluation with existing BufferPool users
h2. Technical Constraints and Requirements
h3. Functional Requirements
* {*}Buffer tracking{*}: Must maintain ability to map buffer slices back to
their original buffers
* {*}Memory management{*}: Must support proper cleanup when buffers are no
longer needed
* {*}Thread safety{*}: Must work correctly in multi-threaded network I/O
scenarios
* {*}Performance{*}: Must not significantly impact network I/O performance
* {*}Backward compatibility{*}: Must maintain existing BufferPool API
h3. Non-Functional Requirements
* {*}Security{*}: Use only public Java APIs
* {*}Maintainability{*}: Solution should be simple and well-documented
* {*}Portability{*}: Work across all supported Java versions (11, 17, 21)
* {*}Memory efficiency{*}: No memory leaks from buffer tracking
* {*}Operational simplicity{*}: No special JVM flags required
h2. Related Work
h3. Similar Issues in Geode
This is part of a broader initiative to eliminate internal API usage:
* GEODE-10519: UnsafeThreadLocal accesses {{java.lang}} internals (requires
{{{}--add-opens{}}})
* AddressableMemoryManager: Accesses {{java.nio}} internals (requires
{{{}--add-opens{}}})
* Other {{sun.{*}{*}}} *and {{com.sun.}}* dependencies requiring module exports
h3. Module System Compliance Initiative
Goal: Make Apache Geode fully compliant with Java Platform Module System:
* Eliminate all {{-{-}add-opens{-}}} and {{-add-exports}} requirements
* Use only public, stable Java APIs
* Improve security posture
* Simplify deployment and operations
* Future-proof against JDK changes
h2. Priority Assessment
*Recommended Priority: Medium-High*
h3. Factors Supporting High Priority
* Security vulnerability from exposing internal NIO implementation
* Maintenance risk from dependency on unstable internal APIs
* Operational complexity from JVM flag requirements
* Compliance issues in enterprise environments
* Technical debt that grows with each JDK release
h3. Factors Supporting Medium Priority
* Current implementation works (with export flags)
* Not causing immediate production failures
* Workaround available (configure JVM flags)
* Other similar issues also need addressing
* Requires careful testing of buffer management
h3. Risk Assessment
{*}If not addressed{*}:
* Risk of breakage in future JDK releases (High probability)
* Continued security audit concerns (Medium impact)
* Ongoing operational complexity (Medium impact)
* Accumulating technical debt (High impact over time)
h2. Success Criteria
* No {{--add-exports=java.base/sun.nio.ch=ALL-UNNAMED}} flag required
* {{geode-unsafe}} module eliminated (or DirectBuffer wrapper removed)
* All buffer pooling functionality maintained
* No performance regression in network I/O
* Works on Java 17, and 21 without special configuration
* Code uses only public Java APIs
* Solution is well-documented and maintainable
h2. Additional Context
h3. Why This Matters
# {*}Security{*}: Exposing {{sun.nio.ch}} internals weakens module boundaries
for critical I/O code
# {*}Maintainability{*}: Internal NIO APIs have changed in past JDK releases,
breaking dependent code
# {*}Compliance{*}: Enterprise security reviews flag internal API usage as
high-risk
# {*}Simplicity{*}: Removing JVM export requirements reduces operational burden
h3. Historical Context
The original {{BufferPool}} implementation was created before the Java module
system existed. When JPMS was introduced in Java 9:
* Internal APIs became encapsulated in modules
* {{sun.*}} packages required explicit export flags
* The {{attachment()}} pattern became a module violation
* A wrapper class was created to isolate the internal access
With modern Java (11+), this approach is no longer sustainable:
* Security concerns have increased
* Module system enforcement is stricter
* Future JDK versions may block internal access entirely
* Better public API solutions are available
h3. Technical Background
*ByteBuffer slice tracking:*
When {{ByteBuffer.slice()}} creates a view of a buffer:
* The slice shares the same backing memory
* The slice doesn't inherently know its "parent" buffer
* The internal {{DirectBuffer.attachment()}} was used to track this
relationship
* This relationship is needed for proper buffer pooling and reuse
*Why tracking is needed:*
* BufferPool manages a pool of large buffers
* Small slices are created for individual messages
* When a slice is released, the original buffer must be returned to the pool
* Proper tracking prevents memory leaks and enables buffer reuse
> Eliminate Reflection-Based Access to java.nio.Buffer Internals in
> AddressableMemoryManager
> ------------------------------------------------------------------------------------------
>
> Key: GEODE-10521
> URL: https://issues.apache.org/jira/browse/GEODE-10521
> Project: Geode
> Issue Type: Improvement
> Reporter: Jinwoo Hwang
> Assignee: Jinwoo Hwang
> Priority: Major
> Fix For: 2.1.0
>
>
> h2. Problem Description
> h3. Current State
> The {{AddressableMemoryManager}} class in {{geode-core}} currently uses
> reflection to access private internal APIs of
> {{{}java.nio.DirectByteBuffer{}}}:
> # {{DirectByteBuffer.address()}} method - to retrieve the native memory
> address from a DirectByteBuffer
> # {{DirectByteBuffer(long, int)}} constructor - to create a DirectByteBuffer
> wrapping a native memory address
> This reflection-based approach requires calling {{setAccessible(true)}} on
> both the method and constructor, which violates Java's module encapsulation
> rules introduced in Java 9 (JEP 260, 261).
> h3. Required JVM Flag
> To allow this reflection at runtime, Apache Geode currently requires the
> following JVM flag:
> {code:java}
> --add-opens=java.base/java.nio=ALL-UNNAMED
> {code}
> This flag is hardcoded in {{MemberJvmOptions.JAVA_11_OPTIONS}} as
> {{JAVA_NIO_OPEN}} and automatically added to all Geode member JVMs running on
> Java 11 and later.
> h3. Code Evidence
> Current implementation in {{{}AddressableMemoryManager.java{}}}:
> {code:java}
> // Reflection-based access requiring --add-opens
> private static volatile Method dbbAddressMethod = null;
> private static volatile Constructor dbbCtor = null;
> public static long getDirectByteBufferAddress(ByteBuffer bb) {
> Method m = dbbAddressMethod;
> if (m == null) {
> m = dbbClass.getDeclaredMethod("address");
> m.setAccessible(true); // REQUIRES --add-opens
> dbbAddressMethod = m;
> }
> return (Long) m.invoke(bb);
> }
> static ByteBuffer createDirectByteBuffer(long address, int size) {
> Constructor ctor = dbbCtor;
> if (ctor == null) {
> ctor = dbbClass.getDeclaredConstructor(long.class, int.class);
> ctor.setAccessible(true); // REQUIRES --add-opens
> dbbCtor = ctor;
> }
> return (ByteBuffer) ctor.newInstance(address, size);
> }
> {code}
> h2. Business Impact
> h3. Security and Compliance Issues
> h4. Java Platform Security Model Violations
> The use of {{--add-opens}} flags represents a security concern and technical
> debt:
> * {*}Strong Encapsulation Bypass{*}: The flag explicitly breaks Java's
> module system encapsulation, which was designed to protect internal
> implementation details
> * {*}Security Manager Conflicts{*}: In environments with security managers
> or restricted permissions, these flags may be blocked or flagged as security
> violations
> * {*}Audit Trail Issues{*}: Security audits and compliance scans flag
> {{--add-opens}} usage as potential vulnerabilities
> * {*}Attack Surface{*}: Opening internal packages to ALL-UNNAMED increases
> the attack surface by allowing any code to access these internals
> h4. Deployment and Operations Impact
> The required JVM flag creates operational friction:
> * {*}Container Security Policies{*}: Many container platforms (Kubernetes,
> Docker Enterprise) have security policies that restrict or audit JVM flags
> * {*}Cloud Platform Restrictions{*}: Some cloud platforms (AWS Lambda, Azure
> Functions, GCP Cloud Run) restrict or monitor JVM flags
> * {*}Enterprise Security Policies{*}: Enterprise security teams often
> require justification and approval for {{--add-opens}} flags
> * {*}Deployment Complexity{*}: Administrators must remember to include the
> flag in all deployment configurations
> h4. Forward Compatibility Risk
> Java's module system evolution poses risks:
> * {*}JEP 403 (Java 17+){*}: Strongly encapsulates JDK internals by default,
> with warnings issued for illegal reflective access
> * {*}Future Java Versions{*}: The Java platform is moving toward stricter
> enforcement of module boundaries
> * {*}Deprecation Path{*}: {{--add-opens}} may become deprecated or
> restricted in future Java releases
> * {*}Migration Cost{*}: The longer this technical debt remains, the more
> costly it becomes to remediate
> h3. Technical Impact
> h4. Off-Heap Memory Management
> {{AddressableMemoryManager}} is a critical component in Geode's off-heap
> memory management:
> * {*}Purpose{*}: Manages direct ByteBuffer access to off-heap memory regions
> * {*}Performance Critical{*}: Used in hot paths for off-heap data access
> * {*}Memory Safety{*}: Provides abstraction layer over native memory
> addresses
> * {*}Zero-Copy Operations{*}: Enables wrapping native memory addresses as
> ByteBuffers without copying data
> Current usage patterns:
> {code:java}
> // Get address from a DirectByteBuffer
> long address = AddressableMemoryManager.getDirectByteBufferAddress(buffer);
> // Create a ByteBuffer wrapping a native memory address
> ByteBuffer wrapper = AddressableMemoryManager.createDirectByteBuffer(address,
> size);
> {code}
> h4. Dependency Chain
> The {{java.nio}} module opening affects multiple components:
> * {{{}geode-core{}}}: Direct usage in {{AddressableMemoryManager}}
> * {{{}geode-gfsh{}}}: Automatic flag injection via {{MemberJvmOptions}}
> * All Geode members: Every server, locator, and client requires the flag
> * Test infrastructure: All integration and unit tests must include the flag
> h2. Benefits of Remediation
> h3. Security and Compliance
> * {*}Eliminates Security Audit Findings{*}: Removes {{--add-opens}} flag
> from security scan results
> * {*}Improves Security Posture{*}: Operates within Java's intended security
> model
> * {*}Simplifies Compliance{*}: Reduces justification burden for security
> teams
> * {*}Future-Proof Security{*}: Aligns with Java platform security evolution
> h3. Operational Excellence
> * {*}Simplified Deployment{*}: One less JVM flag to configure and document
> * {*}Cloud-Native Friendly{*}: Compatible with restrictive cloud platform
> policies
> * {*}Container Security{*}: Passes stricter container security policies
> without exceptions
> * {*}Reduced Configuration Complexity{*}: Fewer deployment-specific
> configurations to maintain
> h3. Java Platform Compatibility
> * {*}Java 17+ Ready{*}: Fully compatible with JEP 403 strong encapsulation
> * {*}Java 21 Forward Compatible{*}: No deprecation warnings or compatibility
> issues
> * {*}Virtual Threads Compatible{*}: Works correctly with Project Loom
> virtual threads
> * {*}GraalVM Native Image Ready{*}: Eliminates reflection that complicates
> native image generation
> h3. Developer Experience
> * {*}Cleaner Code{*}: Less reflection boilerplate and error handling
> * {*}Better IDE Support{*}: IDEs can analyze code without reflection
> indirection
> * {*}Easier Testing{*}: Tests don't require special JVM flag configurations
> * {*}Reduced Maintenance{*}: Eliminates reflection-related failure modes
> h3. Performance Considerations
> * {*}Faster Reflection{*}: Field offset caching is more efficient than
> method reflection
> * {*}JIT Optimization{*}: Direct Unsafe field access optimizes better than
> reflective method invocation
> * {*}Reduced Overhead{*}: Eliminates {{invoke()}} overhead on every call
> * {*}Better Inlining{*}: JIT compiler can inline field access more
> aggressively than reflection
> h2. Module System Context
> This issue is part of a broader initiative to eliminate all JVM module system
> violations in Apache Geode:
> h3. Related Work
> * {*}GEODE-10519{*}: Eliminated
> {{--add-opens=java.base/java.lang=ALL-UNNAMED}} ({{{}UnsafeThreadLocal{}}})
> * {*}GEODE-10520{*}: Eliminated
> {{--add-exports=java.base/sun.nio.ch=ALL-UNNAMED}} ({{{}DirectBuffer{}}})
> * {*}GEODE-10521{*}: This issue - Eliminate
> {{--add-opens=java.base/java.nio=ALL-UNNAMED}}
> ({{{}AddressableMemoryManager{}}})
> * {*}Future{*}:
> {{--add-opens=java.base/com.sun.management.internal=ALL-UNNAMED}}
> ({{{}VMStats50{}}})
> h3. Strategic Goal
> The ultimate goal is to run Apache Geode on Java 17, and 21 without requiring
> any {{-{-}add-opens{-}}} or {{-add-exports}} flags, ensuring:
> * Full compliance with Java module system
> * Maximum security and encapsulation
> * Forward compatibility with future Java releases
> * Cloud-native and container-friendly deployment
> h2. Affected Versions
> * All Geode versions running on Java 17 and later
> * Particularly impacts Java 17+ deployments where strong encapsulation
> warnings appear
> h2. References
> * [JEP 260: Encapsulate Most Internal APIs|https://openjdk.org/jeps/260]
> * [JEP 261: Module System|https://openjdk.org/jeps/261]
> * [JEP 403: Strongly Encapsulate JDK Internals|https://openjdk.org/jeps/403]
> * Java Platform Module System (JPMS) specification
> h2. Additional Context
> h3. Why Reflection Was Used Initially
> The original implementation used reflection because:
> # {{DirectByteBuffer}} constructor is package-private (not accessible)
> # {{DirectByteBuffer.address()}} method is package-private (not accessible)
> # Public {{ByteBuffer}} API doesn't expose native memory address
> # No public API exists to wrap an arbitrary memory address as a ByteBuffer
> This was a pragmatic solution when Java 9 was new and the module system
> implications were less understood.
> h3. Off-Heap Memory Architecture
> Geode's off-heap memory management is critical for large heap scenarios:
> * Reduces garbage collection pressure by keeping data off-heap
> * Enables multi-gigabyte caches without GC pauses
> * Provides direct memory access for serialization/deserialization
> * Supports memory-mapped file operations
> {{AddressableMemoryManager}} is a cornerstone of this architecture, making
> its security and compatibility critical.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)