From ed727cd2c3accf247dc5845b332d76e263555fff Mon Sep 17 00:00:00 2001 From: dhoard Date: Thu, 22 Jan 2026 20:25:04 -0500 Subject: [PATCH 1/2] Hardened argument validation Signed-off-by: dhoard --- pom.xml | 8 ++++ src/main/java/com/tidesdb/Transaction.java | 10 ++--- src/test/java/com/tidesdb/TidesDBTest.java | 43 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index dfae28e..1d8d744 100644 --- a/pom.xml +++ b/pom.xml @@ -50,6 +50,14 @@ ${junit.version} test + + + + org.assertj + assertj-core + 3.27.6 + test + diff --git a/src/main/java/com/tidesdb/Transaction.java b/src/main/java/com/tidesdb/Transaction.java index e787e8d..ef6c1e3 100644 --- a/src/main/java/com/tidesdb/Transaction.java +++ b/src/main/java/com/tidesdb/Transaction.java @@ -51,8 +51,8 @@ public void put(ColumnFamily cf, byte[] key, byte[] value, long ttl) throws Tide if (cf == null) { throw new IllegalArgumentException("Column family cannot be null"); } - if (key == null) { - throw new IllegalArgumentException("Key cannot be null"); + if (key == null || key.length == 0) { + throw new IllegalArgumentException("Key cannot be null or empty"); } if (value == null) { throw new IllegalArgumentException("Value cannot be null"); @@ -85,8 +85,8 @@ public byte[] get(ColumnFamily cf, byte[] key) throws TidesDBException { if (cf == null) { throw new IllegalArgumentException("Column family cannot be null"); } - if (key == null) { - throw new IllegalArgumentException("Key cannot be null"); + if (key == null || key.length == 0) { + throw new IllegalArgumentException("Key cannot be null or empty"); } return nativeGet(nativeHandle, cf.getNativeHandle(), key); } @@ -103,7 +103,7 @@ public void delete(ColumnFamily cf, byte[] key) throws TidesDBException { if (cf == null) { throw new IllegalArgumentException("Column family cannot be null"); } - if (key == null) { + if (key == null || key.length == 0) { throw new IllegalArgumentException("Key cannot be null"); } nativeDelete(nativeHandle, cf.getNativeHandle(), key); diff --git a/src/test/java/com/tidesdb/TidesDBTest.java b/src/test/java/com/tidesdb/TidesDBTest.java index 301b718..a2f681e 100644 --- a/src/test/java/com/tidesdb/TidesDBTest.java +++ b/src/test/java/com/tidesdb/TidesDBTest.java @@ -443,4 +443,47 @@ void testCustomColumnFamilyConfig() throws TidesDBException { assertEquals("custom_cf", cf.getName()); } } + + @Test + @Order(13) + void testTransactionPutGetDeleteBadKey() throws TidesDBException { + Config config = Config.builder(tempDir.resolve("testdb3").toString()) + .numFlushThreads(2) + .numCompactionThreads(2) + .logLevel(LogLevel.INFO) + .blockCacheSize(64 * 1024 * 1024) + .maxOpenSSTables(256) + .build(); + + try (TidesDB db = TidesDB.open(config)) { + ColumnFamilyConfig cfConfig = ColumnFamilyConfig.defaultConfig(); + db.createColumnFamily("test_cf", cfConfig); + + ColumnFamily cf = db.getColumnFamily("test_cf"); + + byte[] key = new byte[0]; // Bad key (empty) + byte[] value = "value".getBytes(StandardCharsets.UTF_8); + + assertThrows(IllegalArgumentException.class, () -> { + try (Transaction txn = db.beginTransaction()) { + txn.put(cf, key, value); + } + }); + + assertThrows(IllegalArgumentException.class, () -> { + try (Transaction txn = db.beginTransaction()) { + byte[] result = txn.get(cf, key); + assertNotNull(result); + assertArrayEquals(value, result); + } + }); + + assertThrows(IllegalArgumentException.class, () -> { + try (Transaction txn = db.beginTransaction()) { + txn.delete(cf, key); + txn.commit(); + } + }); + } + } } From 7eb19c135b57d9730e7295946c5ee94fbc5b74a7 Mon Sep 17 00:00:00 2001 From: dhoard Date: Thu, 22 Jan 2026 20:29:09 -0500 Subject: [PATCH 2/2] Hardened argument validation Signed-off-by: dhoard --- src/main/java/com/tidesdb/TidesDBIterator.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/tidesdb/TidesDBIterator.java b/src/main/java/com/tidesdb/TidesDBIterator.java index fd7a9d7..8e3ce78 100644 --- a/src/main/java/com/tidesdb/TidesDBIterator.java +++ b/src/main/java/com/tidesdb/TidesDBIterator.java @@ -65,8 +65,8 @@ public void seekToLast() throws TidesDBException { */ public void seek(byte[] key) throws TidesDBException { checkNotFreed(); - if (key == null) { - throw new IllegalArgumentException("Key cannot be null"); + if (key == null || key.length == 0) { + throw new IllegalArgumentException("Key cannot be null or empty"); } nativeSeek(nativeHandle, key); } @@ -79,8 +79,8 @@ public void seek(byte[] key) throws TidesDBException { */ public void seekForPrev(byte[] key) throws TidesDBException { checkNotFreed(); - if (key == null) { - throw new IllegalArgumentException("Key cannot be null"); + if (key == null || key.length == 0) { + throw new IllegalArgumentException("Key cannot be null or empty"); } nativeSeekForPrev(nativeHandle, key); }