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