Author: brane
Date: Sun Jan 18 09:08:13 2026
New Revision: 1931402
Log:
Add another test for the Adler-32 implementation. All code branches
should now be covered with tests, even if this new test is a bit
contrived.
* subversion/libsvn_subr/adler32.c
(SVN__ADLER32_SIZE_MAX): Do not define this constant if SVN__ADLER32_STATIC
is defined. This allows adler32-test.c to locally override the maximum
block size.
* subversion/tests/libsvn_subr/adler32-test.c: Add a comment about sorting
the constant arrays that contain test inputs.
(do_random_test): Move common code from the dependent test functions
that call to here.
(test_magic_length, test_prime_length, test_power2_length): Rename from
test_random_magic, test_random_prime and test_random_power2,
respectively; and just call do_random_test.
(local_adler32): New, defined implicitly by including adler32.c
with a modified maximum block size.
(test_large_size): New test case; exercises the unlikely code branch in
our Adler-32 implementation.
(test_funcs): Update the whole array.
Modified:
subversion/trunk/build/generator/gen_base.py
subversion/trunk/subversion/libsvn_subr/adler32.c
subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c
Modified: subversion/trunk/build/generator/gen_base.py
==============================================================================
--- subversion/trunk/build/generator/gen_base.py Sun Jan 18 08:30:14
2026 (r1931401)
+++ subversion/trunk/build/generator/gen_base.py Sun Jan 18 09:08:13
2026 (r1931402)
@@ -1288,6 +1288,9 @@ class IncludeDependencyInfo:
if os.sep.join(['libsvn_subr', 'cmdline.c']) in fname \
and 'config_keys.inc' == include_param:
continue # generated by GeneratorBase.write_config_keys
+ if os.sep.join(['tests', 'libsvn_subr', 'adler32-test.c']) in fname \
+ and '../../libsvn_subr/adler32.c' == include_param:
+ continue # adler32-test.c inludes the source file on purpose
elif direct_possibility_fname in domain_fnames:
self._upd_dep_hash(hdrs, direct_possibility_fname, type_code)
elif (len(domain_fnames) == 1
Modified: subversion/trunk/subversion/libsvn_subr/adler32.c
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/adler32.c Sun Jan 18 08:30:14
2026 (r1931401)
+++ subversion/trunk/subversion/libsvn_subr/adler32.c Sun Jan 18 09:08:13
2026 (r1931402)
@@ -47,10 +47,17 @@ typedef z_size_t svn__adler32_size_t;
#else
typedef uInt svn__adler32_size_t;
#define svn__adler32_impl adler32
-#endif
-#define SVN__ADLER32_SIZE_MAX (~(svn__adler32_size_t)0)
+#endif /* SVN_ZLIB_HAS_ADLER32_Z */
+
#define svn__adler32_fn(c,d,s) svn__adler32_impl((c), (const Bytef *)(d), (s))
+/* See adler32-test.c which invokes dark magic in order to test the
+ (len > SVN__ADLER32_SIZE_MAX) branch of the implementation. */
+#ifndef SVN__ADLER32_STATIC
+#define SVN__ADLER32_STATIC
+#define SVN__ADLER32_SIZE_MAX (~(svn__adler32_size_t)0)
+#endif
+
/*
* 65521 is the largest prime less than 65536.
* "That 65521 is prime is important to avoid a possible large class of
@@ -62,7 +69,7 @@ typedef uInt svn__adler32_size_t;
* Start with CHECKSUM and update the checksum by processing a chunk
* of DATA sized LEN.
*/
-apr_uint32_t
+SVN__ADLER32_STATIC apr_uint32_t
svn__adler32(apr_uint32_t checksum, const char *data, apr_off_t len)
{
/* Process large amounts of data in max-sized chunks.
Modified: subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c Sun Jan
18 08:30:14 2026 (r1931401)
+++ subversion/trunk/subversion/tests/libsvn_subr/adler32-test.c Sun Jan
18 09:08:13 2026 (r1931402)
@@ -51,6 +51,8 @@ static const char *make_random_data(apr_
}
+/* NOTE: The following constant arrays of data sizes must
+ be sorted in ascending order. */
static const apr_off_t magic[8] = {
0, 1, 79, 80, 81, 5551, 5552, 5553
};
@@ -110,59 +112,86 @@ static const apr_off_t power2[66] = {
static svn_error_t *
-do_random_test(apr_uint32_t *seed,
- const apr_off_t lengths[],
+do_random_test(const apr_off_t lengths[],
const apr_size_t array_size,
apr_pool_t *pool)
{
- const char *data = make_random_data(seed, lengths[array_size - 1], pool);
+ apr_uint32_t seed;
+ const apr_off_t length = lengths[array_size - 1];
+ const char *data = make_random_data(&seed, length, pool);
+
+ apr_uint32_t value_from_svn;
+ uLong value_from_zlib;
int i;
for (i = 0; i < array_size; ++i)
{
- apr_uint32_t value_from_svn = svn__adler32(0, data, lengths[i]);
- uLong value_from_zlib = adler32(0, (const Bytef*)data, (uInt)lengths[i]);
- SVN_TEST_ASSERT(value_from_svn == value_from_zlib);
+ /* This will blow up if the lengths array isn't sorted. */
+ SVN_TEST_ASSERT(lengths[i] <= length);
+
+ value_from_svn = svn__adler32(0, data, lengths[i]);
+ value_from_zlib = adler32(0, (const Bytef*)data, (uInt)lengths[i]);
+ if (value_from_svn != value_from_zlib)
+ {
+ fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
+ SVN_TEST_ASSERT(value_from_svn == value_from_zlib);
+ }
}
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_magic_length(apr_pool_t *pool)
+{
+ return do_random_test(magic, sizeof(magic) / sizeof(magic[0]), pool);
+}
static svn_error_t *
-test_random_magic(apr_pool_t *pool)
+test_prime_length(apr_pool_t *pool)
{
- apr_uint32_t seed;
- svn_error_t *err = do_random_test(&seed, magic,
- sizeof(magic) / sizeof(magic[0]),
- pool);
- if (err)
- fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
- return err;
+ return do_random_test(prime, sizeof(prime) / sizeof(prime[0]), pool);
}
static svn_error_t *
-test_random_prime(apr_pool_t *pool)
+test_power2_length(apr_pool_t *pool)
{
- apr_uint32_t seed;
- svn_error_t *err = do_random_test(&seed, prime,
- sizeof(prime) / sizeof(prime[0]),
- pool);
- if (err)
- fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
- return err;
+ return do_random_test(power2, sizeof(power2) / sizeof(power2[0]), pool);
}
+
+/* Insert a static implementation of svn__adler32() with the maximum data
+ size set low enough that we can test the rarely used large-block branch
+ of the code without allocating too many terabytes of memory. */
+#define SVN__ADLER32_STATIC static
+#define svn__adler32 local_adler32
+#define SVN__ADLER32_SIZE_MAX (256U * 256U - 1U) /* 2^16 - 1 = 0xFFFF */
+#include "../../libsvn_subr/adler32.c"
+#undef svn__adler32
+#undef SVN__ADLER32_STATIC
+
static svn_error_t *
-test_random_power2(apr_pool_t *pool)
+test_large_size(apr_pool_t *pool)
{
apr_uint32_t seed;
- svn_error_t *err = do_random_test(&seed, power2,
- sizeof(power2) / sizeof(power2[0]),
- pool);
- if (err)
- fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
- return err;
+ const svn__adler32_size_t length = 256 * 256 * 256; /* 2^24 = 16 MiB */
+ const char *data = make_random_data(&seed, length, pool);
+
+ apr_uint32_t value_from_svn;
+ uLong value_from_zlib;
+
+ SVN_TEST_ASSERT(length > 256 * SVN__ADLER32_SIZE_MAX);
+
+ value_from_svn = local_adler32(0, data, length);
+ value_from_zlib = svn__adler32_fn(0, data, length);
+
+ if (value_from_svn != value_from_zlib)
+ {
+ fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
+ SVN_TEST_ASSERT(value_from_svn == value_from_zlib);
+ }
+
+ return SVN_NO_ERROR;
}
@@ -173,12 +202,14 @@ static int max_threads = 4;
static struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
- SVN_TEST_PASS2(test_random_magic,
- "adler32 random with magic length"),
- SVN_TEST_PASS2(test_random_prime,
- "adler32 random with prime length"),
- SVN_TEST_PASS2(test_random_power2,
- "adler32 random with 2^n length"),
+ SVN_TEST_PASS2(test_magic_length,
+ "adler32 with magic length"),
+ SVN_TEST_PASS2(test_prime_length,
+ "adler32 with prime length"),
+ SVN_TEST_PASS2(test_power2_length,
+ "adler32 with 2^n length"),
+ SVN_TEST_PASS2(test_large_size,
+ "adler32 with data size > block size"),
SVN_TEST_NULL
};