This is an automated email from the ASF dual-hosted git repository.

dcapwell pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-accord.git


The following commit(s) were added to refs/heads/trunk by this push:
     new c9ec676c DefaultLocalListeners.remove adds nulls which then leads to 
NPE when .clear gets called (#285)
c9ec676c is described below

commit c9ec676c4cd3adced869301a38714c827ac9789e
Author: dcapwell <[email protected]>
AuthorDate: Fri Aug 7 12:28:41 2026 -0700

    DefaultLocalListeners.remove adds nulls which then leads to NPE when .clear 
gets called (#285)
    
    patch by Alan Wang, C. Scott Andreas, David Capwell; reviewed by C. Scott 
Andreas, for CASSANDRA-21551
---
 .../src/main/java/accord/impl/DefaultLocalListeners.java  | 10 ++++++++--
 .../src/test/java/accord/impl/LocalListenersTest.java     | 15 +++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/accord-core/src/main/java/accord/impl/DefaultLocalListeners.java 
b/accord-core/src/main/java/accord/impl/DefaultLocalListeners.java
index 02bd617b..43fd39cd 100644
--- a/accord-core/src/main/java/accord/impl/DefaultLocalListeners.java
+++ b/accord-core/src/main/java/accord/impl/DefaultLocalListeners.java
@@ -558,8 +558,14 @@ public class DefaultLocalListeners implements 
LocalListeners
             RegisteredComplexListeners listeners = 
complexListeners.remove(key);
             if (listeners != null)
             {
-                for (int i = 0 ; i < listeners.count ; i++)
-                    listeners.listeners[i].index = -1;
+                if (Invariants.isParanoid()) listeners.checkIntegrity();
+                // On removal listeners contains nulls, so skip
+                for (int i = 0 ; i < listeners.length ; i++)
+                {
+                    RegisteredComplexListener l = listeners.listeners[i];
+                    if (l != null)
+                        l.index = -1;
+                }
             }
         });
     }
diff --git a/accord-core/src/test/java/accord/impl/LocalListenersTest.java 
b/accord-core/src/test/java/accord/impl/LocalListenersTest.java
index 8ac0a0bb..9556e6db 100644
--- a/accord-core/src/test/java/accord/impl/LocalListenersTest.java
+++ b/accord-core/src/test/java/accord/impl/LocalListenersTest.java
@@ -466,6 +466,21 @@ public class LocalListenersTest
         Assertions.assertEquals(expected, actual);
     }
 
+    @Test
+    public void testClearWithNullHoleFromCancelledComplexListener()
+    {
+        DefaultLocalListeners listeners = new DefaultLocalListeners(null, new 
NoOpRemoteListeners(), null);
+        TxnId txnId1 = new TxnId(1, 1, Txn.Kind.Write, Routable.Domain.Key, 
new Node.Id(1));
+
+        ComplexListener listener = (safeStore, safeCommand) -> false;
+        LocalListeners.Registered registeredA = listeners.register(txnId1, 
listener);
+        listeners.register(txnId1, listener);
+        registeredA.cancel();
+
+        // CASSANDRA-21551: when a listener was removed a null was inserted 
and clear didn't have null checks so this would fail
+        Assertions.assertDoesNotThrow(listeners::clear);
+    }
+
     @Test
     public void testComplexListeners()
     {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to