1 1.1 christos // SPDX-License-Identifier: 0BSD 2 1.1 christos 3 1.1 christos /////////////////////////////////////////////////////////////////////////////// 4 1.1 christos // 5 1.1 christos /// \file test_index_hash.c 6 1.1 christos /// \brief Tests src/liblzma/common/index_hash.c API functions 7 1.1 christos /// 8 1.1 christos /// \note No test included for lzma_index_hash_end since it 9 1.1 christos /// would be trivial unless tested for memory leaks 10 1.1 christos /// with something like valgrind 11 1.1 christos // 12 1.1 christos // Author: Jia Tan 13 1.1 christos // 14 1.1 christos /////////////////////////////////////////////////////////////////////////////// 15 1.1 christos 16 1.1 christos #include "tests.h" 17 1.1 christos 18 1.1 christos // Needed for UNPADDED_SIZE_MIN and UNPADDED_SIZE_MAX macro definitions 19 1.1 christos // and index_size and vli_ceil4 helper functions 20 1.1 christos #include "common/index.h" 21 1.1 christos 22 1.1 christos 23 1.1 christos static void 24 1.1 christos test_lzma_index_hash_init(void) 25 1.1 christos { 26 1.1 christos #ifndef HAVE_DECODERS 27 1.1 christos assert_skip("Decoder support disabled"); 28 1.1 christos #else 29 1.1 christos // First test with NULL index_hash. 30 1.1 christos // This should create a fresh index_hash. 31 1.1 christos lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL); 32 1.1 christos assert_true(index_hash != NULL); 33 1.1 christos 34 1.1 christos // Next test with non-NULL index_hash. 35 1.1 christos lzma_index_hash *second_hash = lzma_index_hash_init(index_hash, NULL); 36 1.1 christos 37 1.1 christos // It should not create a new index_hash pointer. 38 1.1 christos // Instead it must just re-init the first index_hash. 39 1.1 christos assert_true(index_hash == second_hash); 40 1.1 christos 41 1.1 christos lzma_index_hash_end(index_hash, NULL); 42 1.1 christos #endif 43 1.1 christos } 44 1.1 christos 45 1.1 christos 46 1.1 christos static void 47 1.1 christos test_lzma_index_hash_append(void) 48 1.1 christos { 49 1.1 christos #ifndef HAVE_DECODERS 50 1.1 christos assert_skip("Decoder support disabled"); 51 1.1 christos #else 52 1.1 christos // Test all invalid parameters 53 1.1 christos assert_lzma_ret(lzma_index_hash_append(NULL, 0, 0), 54 1.1 christos LZMA_PROG_ERROR); 55 1.1 christos 56 1.1 christos // Test NULL index_hash 57 1.1 christos assert_lzma_ret(lzma_index_hash_append(NULL, UNPADDED_SIZE_MIN, 58 1.1 christos LZMA_VLI_MAX), LZMA_PROG_ERROR); 59 1.1 christos 60 1.1 christos // Test with invalid Unpadded Size 61 1.1 christos lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL); 62 1.1 christos assert_true(index_hash != NULL); 63 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 64 1.1 christos UNPADDED_SIZE_MIN - 1, LZMA_VLI_MAX), 65 1.1 christos LZMA_PROG_ERROR); 66 1.1 christos 67 1.1 christos // Test with invalid Uncompressed Size 68 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 69 1.1 christos UNPADDED_SIZE_MIN, LZMA_VLI_MAX + 1), 70 1.1 christos LZMA_PROG_ERROR); 71 1.1 christos 72 1.1 christos // First append a Record describing a small Block. 73 1.1 christos // This should succeed. 74 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 75 1.1 christos UNPADDED_SIZE_MIN, 1), LZMA_OK); 76 1.1 christos 77 1.1 christos // Append another small Record. 78 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 79 1.1 christos UNPADDED_SIZE_MIN, 1), LZMA_OK); 80 1.1 christos 81 1.1 christos // Append a Record that would cause the compressed size to grow 82 1.1 christos // too big 83 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 84 1.1 christos UNPADDED_SIZE_MAX, 1), LZMA_DATA_ERROR); 85 1.1 christos 86 1.1 christos lzma_index_hash_end(index_hash, NULL); 87 1.1 christos #endif 88 1.1 christos } 89 1.1 christos 90 1.1 christos 91 1.1 christos #if defined(HAVE_ENCODERS) && defined(HAVE_DECODERS) 92 1.1 christos // Fill an index_hash with unpadded and uncompressed VLIs 93 1.1 christos // by calling lzma_index_hash_append 94 1.1 christos static void 95 1.1 christos fill_index_hash(lzma_index_hash *index_hash, const lzma_vli *unpadded_sizes, 96 1.1 christos const lzma_vli *uncomp_sizes, uint32_t block_count) 97 1.1 christos { 98 1.1 christos for (uint32_t i = 0; i < block_count; ++i) 99 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 100 1.1 christos unpadded_sizes[i], uncomp_sizes[i]), LZMA_OK); 101 1.1 christos } 102 1.1 christos 103 1.1 christos 104 1.1 christos // Set the contents of buf to the expected Index based on the 105 1.1 christos // .xz specification. This needs the unpadded and uncompressed VLIs 106 1.1 christos // to correctly create the Index. 107 1.1 christos static void 108 1.1 christos generate_index(uint8_t *buf, const lzma_vli *unpadded_sizes, 109 1.1 christos const lzma_vli *uncomp_sizes, uint32_t block_count, 110 1.1 christos size_t index_max_size) 111 1.1 christos { 112 1.1 christos size_t in_pos = 0; 113 1.1 christos size_t out_pos = 0; 114 1.1 christos 115 1.1 christos // First set Index Indicator 116 1.1 christos buf[out_pos++] = INDEX_INDICATOR; 117 1.1 christos 118 1.1 christos // Next write out Number of Records 119 1.1 christos assert_lzma_ret(lzma_vli_encode(block_count, &in_pos, buf, 120 1.1 christos &out_pos, index_max_size), LZMA_STREAM_END); 121 1.1 christos 122 1.1 christos // Next write out each Record. 123 1.1 christos // A Record consists of Unpadded Size and Uncompressed Size 124 1.1 christos // written next to each other as VLIs. 125 1.1 christos for (uint32_t i = 0; i < block_count; ++i) { 126 1.1 christos in_pos = 0; 127 1.1 christos assert_lzma_ret(lzma_vli_encode(unpadded_sizes[i], &in_pos, 128 1.1 christos buf, &out_pos, index_max_size), LZMA_STREAM_END); 129 1.1 christos in_pos = 0; 130 1.1 christos assert_lzma_ret(lzma_vli_encode(uncomp_sizes[i], &in_pos, 131 1.1 christos buf, &out_pos, index_max_size), LZMA_STREAM_END); 132 1.1 christos } 133 1.1 christos 134 1.1 christos // Add Index Padding 135 1.1 christos lzma_vli rounded_out_pos = vli_ceil4(out_pos); 136 1.1 christos memzero(buf + out_pos, rounded_out_pos - out_pos); 137 1.1 christos out_pos = rounded_out_pos; 138 1.1 christos 139 1.1 christos // Add the CRC32 140 1.1 christos write32le(buf + out_pos, lzma_crc32(buf, out_pos, 0)); 141 1.1 christos out_pos += 4; 142 1.1 christos 143 1.1 christos assert_uint_eq(out_pos, index_max_size); 144 1.1 christos } 145 1.1 christos #endif 146 1.1 christos 147 1.1 christos 148 1.1 christos static void 149 1.1 christos test_lzma_index_hash_decode(void) 150 1.1 christos { 151 1.1 christos #if !defined(HAVE_ENCODERS) || !defined(HAVE_DECODERS) 152 1.1 christos assert_skip("Encoder or decoder support disabled"); 153 1.1 christos #else 154 1.1 christos lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL); 155 1.1 christos assert_true(index_hash != NULL); 156 1.1 christos 157 1.1 christos size_t in_pos = 0; 158 1.1 christos 159 1.1 christos // Six valid values for the Unpadded Size fields in an Index 160 1.1 christos const lzma_vli unpadded_sizes[6] = { 161 1.1 christos UNPADDED_SIZE_MIN, 162 1.1 christos 1000, 163 1.1 christos 4000, 164 1.1 christos 8000, 165 1.1 christos 16000, 166 1.1 christos 32000 167 1.1 christos }; 168 1.1 christos 169 1.1 christos // Six valid values for the Uncompressed Size fields in an Index 170 1.1 christos const lzma_vli uncomp_sizes[6] = { 171 1.1 christos 1, 172 1.1 christos 500, 173 1.1 christos 8000, 174 1.1 christos 20, 175 1.1 christos 1, 176 1.1 christos 500 177 1.1 christos }; 178 1.1 christos 179 1.1 christos // Add two Records to an index_hash 180 1.1 christos fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2); 181 1.1 christos 182 1.1 christos const lzma_vli size_two_records = lzma_index_hash_size(index_hash); 183 1.1 christos assert_uint(size_two_records, >, 0); 184 1.1 christos uint8_t *index_two_records = tuktest_malloc(size_two_records); 185 1.1 christos 186 1.1 christos generate_index(index_two_records, unpadded_sizes, uncomp_sizes, 2, 187 1.1 christos size_two_records); 188 1.1 christos 189 1.1 christos // First test for basic buffer size error 190 1.1 christos in_pos = size_two_records + 1; 191 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 192 1.1 christos index_two_records, &in_pos, 193 1.1 christos size_two_records), LZMA_BUF_ERROR); 194 1.1 christos 195 1.1 christos // Next test for invalid Index Indicator 196 1.1 christos in_pos = 0; 197 1.1 christos index_two_records[0] ^= 1; 198 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 199 1.1 christos index_two_records, &in_pos, 200 1.1 christos size_two_records), LZMA_DATA_ERROR); 201 1.1 christos index_two_records[0] ^= 1; 202 1.1 christos 203 1.1 christos // Next verify the index_hash as expected 204 1.1 christos in_pos = 0; 205 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 206 1.1 christos index_two_records, &in_pos, 207 1.1 christos size_two_records), LZMA_STREAM_END); 208 1.1 christos 209 1.1 christos // Next test an index_hash with three Records 210 1.1 christos index_hash = lzma_index_hash_init(index_hash, NULL); 211 1.1 christos fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 3); 212 1.1 christos 213 1.1 christos const lzma_vli size_three_records = lzma_index_hash_size( 214 1.1 christos index_hash); 215 1.1 christos assert_uint(size_three_records, >, 0); 216 1.1 christos uint8_t *index_three_records = tuktest_malloc(size_three_records); 217 1.1 christos 218 1.1 christos generate_index(index_three_records, unpadded_sizes, uncomp_sizes, 219 1.1 christos 3, size_three_records); 220 1.1 christos 221 1.1 christos in_pos = 0; 222 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 223 1.1 christos index_three_records, &in_pos, 224 1.1 christos size_three_records), LZMA_STREAM_END); 225 1.1 christos 226 1.1 christos // Next test an index_hash with five Records 227 1.1 christos index_hash = lzma_index_hash_init(index_hash, NULL); 228 1.1 christos fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5); 229 1.1 christos 230 1.1 christos const lzma_vli size_five_records = lzma_index_hash_size( 231 1.1 christos index_hash); 232 1.1 christos assert_uint(size_five_records, >, 0); 233 1.1 christos uint8_t *index_five_records = tuktest_malloc(size_five_records); 234 1.1 christos 235 1.1 christos generate_index(index_five_records, unpadded_sizes, uncomp_sizes, 5, 236 1.1 christos size_five_records); 237 1.1 christos 238 1.1 christos // Instead of testing all input at once, give input 239 1.1 christos // one byte at a time 240 1.1 christos in_pos = 0; 241 1.1 christos for (lzma_vli i = 0; i < size_five_records - 1; ++i) { 242 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 243 1.1 christos index_five_records, &in_pos, in_pos + 1), 244 1.1 christos LZMA_OK); 245 1.1 christos } 246 1.1 christos 247 1.1 christos // Last byte should return LZMA_STREAM_END 248 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 249 1.1 christos index_five_records, &in_pos, 250 1.1 christos in_pos + 1), LZMA_STREAM_END); 251 1.1 christos 252 1.1 christos // Next test if the index_hash is given an incorrect Unpadded 253 1.1 christos // Size. Should detect and report LZMA_DATA_ERROR 254 1.1 christos index_hash = lzma_index_hash_init(index_hash, NULL); 255 1.1 christos fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 5); 256 1.1 christos // The sixth Record will have an invalid Unpadded Size 257 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 258 1.1 christos unpadded_sizes[5] + 1, 259 1.1 christos uncomp_sizes[5]), LZMA_OK); 260 1.1 christos 261 1.1 christos const lzma_vli size_six_records = lzma_index_hash_size( 262 1.1 christos index_hash); 263 1.1 christos 264 1.1 christos assert_uint(size_six_records, >, 0); 265 1.1 christos uint8_t *index_six_records = tuktest_malloc(size_six_records); 266 1.1 christos 267 1.1 christos generate_index(index_six_records, unpadded_sizes, uncomp_sizes, 6, 268 1.1 christos size_six_records); 269 1.1 christos in_pos = 0; 270 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 271 1.1 christos index_six_records, &in_pos, 272 1.1 christos size_six_records), LZMA_DATA_ERROR); 273 1.1 christos 274 1.1 christos // Next test if the Index is corrupt (invalid CRC32). 275 1.1 christos // Should detect and report LZMA_DATA_ERROR 276 1.1 christos index_hash = lzma_index_hash_init(index_hash, NULL); 277 1.1 christos fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2); 278 1.1 christos 279 1.1 christos index_two_records[size_two_records - 1] ^= 1; 280 1.1 christos 281 1.1 christos in_pos = 0; 282 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 283 1.1 christos index_two_records, &in_pos, 284 1.1 christos size_two_records), LZMA_DATA_ERROR); 285 1.1 christos 286 1.1 christos // Next test with Index and index_hash struct not matching 287 1.1 christos // a Record 288 1.1 christos index_hash = lzma_index_hash_init(index_hash, NULL); 289 1.1 christos fill_index_hash(index_hash, unpadded_sizes, uncomp_sizes, 2); 290 1.1 christos // Recalculate Index with invalid Unpadded Size 291 1.1 christos const lzma_vli unpadded_sizes_invalid[2] = { 292 1.1 christos unpadded_sizes[0], 293 1.1 christos unpadded_sizes[1] + 1 294 1.1 christos }; 295 1.1 christos 296 1.1 christos generate_index(index_two_records, unpadded_sizes_invalid, 297 1.1 christos uncomp_sizes, 2, size_two_records); 298 1.1 christos 299 1.1 christos in_pos = 0; 300 1.1 christos assert_lzma_ret(lzma_index_hash_decode(index_hash, 301 1.1 christos index_two_records, &in_pos, 302 1.1 christos size_two_records), LZMA_DATA_ERROR); 303 1.1 christos 304 1.1 christos lzma_index_hash_end(index_hash, NULL); 305 1.1 christos #endif 306 1.1 christos } 307 1.1 christos 308 1.1 christos 309 1.1 christos static void 310 1.1 christos test_lzma_index_hash_size(void) 311 1.1 christos { 312 1.1 christos #ifndef HAVE_DECODERS 313 1.1 christos assert_skip("Decoder support disabled"); 314 1.1 christos #else 315 1.1 christos lzma_index_hash *index_hash = lzma_index_hash_init(NULL, NULL); 316 1.1 christos assert_true(index_hash != NULL); 317 1.1 christos 318 1.1 christos // First test empty index_hash 319 1.1 christos // Expected size should be: 320 1.1 christos // Index Indicator - 1 byte 321 1.1 christos // Number of Records - 1 byte 322 1.1 christos // List of Records - 0 bytes 323 1.1 christos // Index Padding - 2 bytes 324 1.1 christos // CRC32 - 4 bytes 325 1.1 christos // Total - 8 bytes 326 1.1 christos assert_uint_eq(lzma_index_hash_size(index_hash), 8); 327 1.1 christos 328 1.1 christos // Append a Record describing a small Block to the index_hash 329 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 330 1.1 christos UNPADDED_SIZE_MIN, 1), LZMA_OK); 331 1.1 christos 332 1.1 christos // Expected size should be: 333 1.1 christos // Index Indicator - 1 byte 334 1.1 christos // Number of Records - 1 byte 335 1.1 christos // List of Records - 2 bytes 336 1.1 christos // Index Padding - 0 bytes 337 1.1 christos // CRC32 - 4 bytes 338 1.1 christos // Total - 8 bytes 339 1.1 christos lzma_vli expected_size = 8; 340 1.1 christos assert_uint_eq(lzma_index_hash_size(index_hash), expected_size); 341 1.1 christos 342 1.1 christos // Append additional small Record 343 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 344 1.1 christos UNPADDED_SIZE_MIN, 1), LZMA_OK); 345 1.1 christos 346 1.1 christos // Expected size should be: 347 1.1 christos // Index Indicator - 1 byte 348 1.1 christos // Number of Records - 1 byte 349 1.1 christos // List of Records - 4 bytes 350 1.1 christos // Index Padding - 2 bytes 351 1.1 christos // CRC32 - 4 bytes 352 1.1 christos // Total - 12 bytes 353 1.1 christos expected_size = 12; 354 1.1 christos assert_uint_eq(lzma_index_hash_size(index_hash), expected_size); 355 1.1 christos 356 1.1 christos // Append a larger Record to the index_hash (3 bytes for each VLI) 357 1.1 christos const lzma_vli three_byte_vli = 0x10000; 358 1.1 christos assert_lzma_ret(lzma_index_hash_append(index_hash, 359 1.1 christos three_byte_vli, three_byte_vli), LZMA_OK); 360 1.1 christos 361 1.1 christos // Expected size should be: 362 1.1 christos // Index Indicator - 1 byte 363 1.1 christos // Number of Records - 1 byte 364 1.1 christos // List of Records - 10 bytes 365 1.1 christos // Index Padding - 0 bytes 366 1.1 christos // CRC32 - 4 bytes 367 1.1 christos // Total - 16 bytes 368 1.1 christos expected_size = 16; 369 1.1 christos assert_uint_eq(lzma_index_hash_size(index_hash), expected_size); 370 1.1 christos 371 1.1 christos lzma_index_hash_end(index_hash, NULL); 372 1.1 christos #endif 373 1.1 christos } 374 1.1 christos 375 1.1 christos 376 1.1 christos extern int 377 1.1 christos main(int argc, char **argv) 378 1.1 christos { 379 1.1 christos tuktest_start(argc, argv); 380 1.1 christos tuktest_run(test_lzma_index_hash_init); 381 1.1 christos tuktest_run(test_lzma_index_hash_append); 382 1.1 christos tuktest_run(test_lzma_index_hash_decode); 383 1.1 christos tuktest_run(test_lzma_index_hash_size); 384 1.1 christos return tuktest_end(); 385 1.1 christos } 386