int repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
while (repeats >= 12) {
charnum += 3 * 12;
- if (ip <= iend-7) {
+ if (LIKELY(ip <= iend-7)) {
ip += 3;
- bitStream = MEM_readLE32(ip) >> bitCount;
} else {
- bitStream >>= 24;
- bitCount += 24;
+ bitCount -= (int)(8 * (iend - 7 - ip));
+ bitCount &= 31;
+ ip = iend - 4;
}
+ bitStream = MEM_readLE32(ip) >> bitCount;
repeats = FSE_ctz(~bitStream | 0x80000000) >> 1;
}
charnum += 3 * repeats;
bitCount += 2 * repeats;
/* Add the final repeat which isn't 0b11. */
+ assert((bitStream & 3) < 3);
charnum += bitStream & 3;
bitCount += 2;
* because we already memset the whole buffer to 0.
*/
- if ((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
+ if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
assert((bitCount >> 3) <= 3); /* For first condition to work */
ip += bitCount>>3;
bitCount &= 7;
- bitStream = MEM_readLE32(ip) >> bitCount;
} else {
- bitStream >>= 2;
+ bitCount -= (int)(8 * (iend - 4 - ip));
+ bitCount &= 31;
+ ip = iend - 4;
}
+ bitStream = MEM_readLE32(ip) >> bitCount;
}
{
int const max = (2*threshold-1) - remaining;
}
if (charnum >= maxSV1) break;
- if (LIKELY((ip <= iend-7) || (ip + (bitCount>>3) <= iend-4))) {
+ if (LIKELY(ip <= iend-7) || (ip + (bitCount>>3) <= iend-4)) {
ip += bitCount>>3;
bitCount &= 7;
} else {
bitCount -= (int)(8 * (iend - 4 - ip));
+ bitCount &= 31;
ip = iend - 4;
}
- bitStream = MEM_readLE32(ip) >> (bitCount & 31);
+ bitStream = MEM_readLE32(ip) >> bitCount;
} }
if (remaining != 1) return ERROR(corruption_detected);
/* Only possible when there are too many zeros. */
--- /dev/null
+/*
+ * Copyright (c) 2016-2020, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE file in the root directory of this source tree) and the GPLv2 (found
+ * in the COPYING file in the root directory of this source tree).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/**
+ * This fuzz target round trips the FSE normalized count with FSE_writeNCount()
+ * and FSE_readNcount() to ensure that it can always round trip correctly.
+ */
+
+#define FSE_STATIC_LINKING_ONLY
+#define ZSTD_STATIC_LINKING_ONLY
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "fuzz_helpers.h"
+#include "zstd_helpers.h"
+#include "fuzz_data_producer.h"
+#include "fse.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
+{
+ FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size);
+
+ /* Pick a random tableLog and maxSymbolValue */
+ unsigned const tableLog = FUZZ_dataProducer_uint32Range(producer, FSE_MIN_TABLELOG, FSE_MAX_TABLELOG);
+ unsigned const maxSymbolValue = FUZZ_dataProducer_uint32Range(producer, 0, 255);
+
+ unsigned remainingWeight = (1u << tableLog) - 1;
+ size_t dataSize;
+ BYTE data[512];
+ short ncount[256];
+
+ /* Randomly fill the normalized count */
+ memset(ncount, 0, sizeof(ncount));
+ {
+ unsigned s;
+ for (s = 0; s < maxSymbolValue && remainingWeight > 0; ++s) {
+ short n = (short)FUZZ_dataProducer_int32Range(producer, -1, remainingWeight);
+ ncount[s] = n;
+ if (n < 0) {
+ remainingWeight -= 1;
+ } else {
+ assert((unsigned)n <= remainingWeight);
+ remainingWeight -= n;
+ }
+ }
+ /* Ensure ncount[maxSymbolValue] != 0 and the sum is (1<<tableLog) */
+ ncount[maxSymbolValue] = remainingWeight + 1;
+ if (ncount[maxSymbolValue] == 1 && FUZZ_dataProducer_uint32Range(producer, 0, 1) == 1) {
+ ncount[maxSymbolValue] = -1;
+ }
+ }
+ /* Write the normalized count */
+ {
+ FUZZ_ASSERT(sizeof(data) >= FSE_NCountWriteBound(maxSymbolValue, tableLog));
+ dataSize = FSE_writeNCount(data, sizeof(data), ncount, maxSymbolValue, tableLog);
+ FUZZ_ZASSERT(dataSize);
+ }
+ /* Read & validate the normalized count */
+ {
+ short rtNcount[256];
+ unsigned rtMaxSymbolValue = 255;
+ unsigned rtTableLog;
+ /* Copy into a buffer with a random amount of random data at the end */
+ size_t const buffSize = (size_t)FUZZ_dataProducer_uint32Range(producer, dataSize, sizeof(data));
+ BYTE* const buff = FUZZ_malloc(buffSize);
+ size_t rtDataSize;
+ memcpy(buff, data, dataSize);
+ {
+ size_t b;
+ for (b = dataSize; b < buffSize; ++b) {
+ buff[b] = (BYTE)FUZZ_dataProducer_uint32Range(producer, 0, 255);
+ }
+ }
+
+ rtDataSize = FSE_readNCount(rtNcount, &rtMaxSymbolValue, &rtTableLog, buff, buffSize);
+ FUZZ_ZASSERT(rtDataSize);
+ FUZZ_ASSERT(rtDataSize == dataSize);
+ FUZZ_ASSERT(rtMaxSymbolValue == maxSymbolValue);
+ FUZZ_ASSERT(rtTableLog == tableLog);
+ {
+ unsigned s;
+ for (s = 0; s <= maxSymbolValue; ++s) {
+ FUZZ_ASSERT(ncount[s] == rtNcount[s]);
+ }
+ }
+ free(buff);
+ }
+
+ FUZZ_dataProducer_free(producer);
+ return 0;
+}