From 9f96b71b014e7b113dbb35a989b54709342ee69a Mon Sep 17 00:00:00 2001 From: Ziya Kapoor Date: Thu, 22 Oct 2026 20:16:22 +0530 Subject: [PATCH] Reject undersized map in FrequentLongsSketch.getInstance(String) --- .../frequencies/FrequentLongsSketch.java | 10 ++++++ .../frequencies/LongsSketchTest.java | 31 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/main/java/org/apache/datasketches/frequencies/FrequentLongsSketch.java b/src/main/java/org/apache/datasketches/frequencies/FrequentLongsSketch.java index 81fba6fc8..001e80ad2 100644 --- a/src/main/java/org/apache/datasketches/frequencies/FrequentLongsSketch.java +++ b/src/main/java/org/apache/datasketches/frequencies/FrequentLongsSketch.java @@ -335,6 +335,16 @@ public static FrequentLongsSketch getInstance(final String string) { "Possible Corruption: Incorrect # of tokens: " + numTokens + ", numActive: " + numActive); } + if (lgCur < LG_MIN_MAP_SIZE) { + throw new SketchesArgumentException( + "Possible Corruption: Map length must be at least " + (1 << LG_MIN_MAP_SIZE) + ": " + + tokens[STR_PREAMBLE_TOKENS + 1]); + } + final long maxActive = (long) ((1L << lgCur) * ReversePurgeLongHashMap.getLoadFactor()); + if ((numActive < 0) || (numActive > maxActive)) { + throw new SketchesArgumentException( + "Possible Corruption: numActive exceeds map capacity: " + numActive); + } final FrequentLongsSketch sketch = new FrequentLongsSketch(lgMax, lgCur); sketch.streamWeight = streamWt; diff --git a/src/test/java/org/apache/datasketches/frequencies/LongsSketchTest.java b/src/test/java/org/apache/datasketches/frequencies/LongsSketchTest.java index 4df537c93..650405751 100644 --- a/src/test/java/org/apache/datasketches/frequencies/LongsSketchTest.java +++ b/src/test/java/org/apache/datasketches/frequencies/LongsSketchTest.java @@ -577,6 +577,37 @@ public void checkStringDeserEmptyFlagWithStreamLength() { FrequentLongsSketch.getInstance(s); } + @Test(expectedExceptions = SketchesArgumentException.class, timeOut = 5000) + public void checkStringDeserMapLengthTooSmall() { + final String s = "1," //serVer + + "10," //FamID + + "3," //lgMaxMapSz + + "5," //Empty Flag + + "0," //stream Len: empty + + "0," //error offset + + "0," //numActive + + "2,"; //curMapLen ... corrupted, below the minimum of 8 + final FrequentLongsSketch fls = FrequentLongsSketch.getInstance(s); + fls.update(1); + fls.update(2); + fls.update(3); + } + + @Test(expectedExceptions = SketchesArgumentException.class, timeOut = 5000) + public void checkStringDeserNumActiveExceedsMapCapacity() { + final StringBuilder sb = new StringBuilder(); + sb.append("1,") //serVer + .append("10,") //FamID + .append("3,") //lgMaxMapSz + .append("0,") //Empty Flag = false + .append("9,") //stream Len + .append("0,") //error offset + .append("9,") //numActive ... corrupted, more than the map can hold + .append("8,"); //curMapLen + for (int i = 1; i <= 9; i++) { sb.append(i).append(",1,"); } + FrequentLongsSketch.getInstance(sb.toString()); + } + @Test public void checkGetEpsilon() { assertEquals(FrequentLongsSketch.getEpsilon(1024), 3.5 / 1024, 0.0);