|
48 | 48 | #include <chunkio/cio_stream.h> |
49 | 49 | #include <chunkio/cio_chunk.h> |
50 | 50 |
|
| 51 | +/* Note: We still need to include cio_file_native.h for testing native functions |
| 52 | + * directly to verify bug fixes, but we use public APIs for state checks */ |
| 53 | + |
51 | 54 | #include "cio_tests_internal.h" |
52 | 55 |
|
53 | 56 | #define CIO_ENV "tmp" |
@@ -101,10 +104,11 @@ static void test_win32_delete_while_open() |
101 | 104 | cf = (struct cio_file *) chunk->backend; |
102 | 105 | TEST_CHECK(cf != NULL); |
103 | 106 |
|
104 | | - /* Verify file is open */ |
105 | | - TEST_CHECK(cio_file_native_is_open(cf) == 1); |
| 107 | + /* Verify file is open (using public API) */ |
| 108 | + TEST_CHECK(cio_chunk_is_up(chunk) == CIO_TRUE); |
106 | 109 |
|
107 | 110 | /* Try to delete while open - THIS SHOULD FAIL but currently doesn't on Windows */ |
| 111 | + /* Note: We use native function here to test the bug directly */ |
108 | 112 | ret = cio_file_native_delete(cf); |
109 | 113 | printf("Result of delete while open: %d (expected: CIO_ERROR=%d)\n", |
110 | 114 | ret, CIO_ERROR); |
@@ -163,8 +167,8 @@ static void test_win32_delete_while_mapped() |
163 | 167 | ret = cio_chunk_write(chunk, "test data", 9); |
164 | 168 | TEST_CHECK(ret == 0); |
165 | 169 |
|
166 | | - /* Verify file is mapped */ |
167 | | - TEST_CHECK(cio_file_native_is_mapped(cf) == 1); |
| 170 | + /* Verify file is mapped (using public API) */ |
| 171 | + TEST_CHECK(cio_chunk_is_up(chunk) == CIO_TRUE); |
168 | 172 |
|
169 | 173 | /* Try to delete while mapped - THIS SHOULD FAIL but currently doesn't on Windows */ |
170 | 174 | ret = cio_file_native_delete(cf); |
@@ -222,40 +226,31 @@ static void test_win32_sync_without_map() |
222 | 226 | cf = (struct cio_file *) chunk->backend; |
223 | 227 | TEST_CHECK(cf != NULL); |
224 | 228 |
|
225 | | - /* Manually unmap if it was auto-mapped */ |
226 | | - if (cio_file_native_is_mapped(cf)) { |
227 | | - ret = cio_file_native_unmap(cf); |
228 | | - TEST_CHECK(ret == CIO_OK); |
| 229 | + /* Manually unmap if it was auto-mapped (using public API) */ |
| 230 | + if (cio_chunk_is_up(chunk) == CIO_TRUE) { |
| 231 | + ret = cio_file_down(chunk); |
| 232 | + TEST_CHECK(ret == 0); |
229 | 233 | } |
230 | 234 |
|
231 | | - /* Verify file is not mapped */ |
232 | | - TEST_CHECK(cio_file_native_is_mapped(cf) == 0); |
233 | | - |
234 | | - /* Verify cf->map is actually NULL (this is the issue) */ |
235 | | - TEST_CHECK(cf->map == NULL); |
236 | | - printf("Verified: cf->map is NULL\n"); |
237 | | - |
238 | | - /* Try to sync without mapping - THIS SHOULD CHECK FIRST */ |
239 | | - /* On Windows, cio_file_native_sync accesses cf->map directly without checking */ |
240 | | - /* This will likely cause a crash or access violation because FlushViewOfFile |
241 | | - * is called with a NULL pointer */ |
242 | | - printf("Attempting sync on unmapped file (cf->map is NULL)...\n"); |
243 | | - printf("WARNING: cio_file_native_sync will call FlushViewOfFile(cf->map, ...)\n"); |
244 | | - printf(" which will fail or crash if cf->map is NULL\n"); |
245 | | - |
246 | | - /* This test is designed to highlight the issue - on Windows it may crash */ |
247 | | - /* On Windows, cio_file_native_sync accesses cf->map without checking if NULL */ |
248 | | - /* This TEST_CHECK will FAIL in CI if sync succeeds or crashes, highlighting the issue */ |
249 | | - /* Note: If it crashes, the test will fail anyway */ |
250 | | - ret = cio_file_native_sync(cf, 0); |
251 | | - printf("Result of sync without map: %d (expected: CIO_ERROR=%d)\n", ret, CIO_ERROR); |
252 | | - |
253 | | - /* Expected: CIO_ERROR due to NULL map pointer */ |
254 | | - /* This TEST_CHECK will FAIL in CI, highlighting the inconsistency */ |
255 | | - TEST_CHECK(ret == CIO_ERROR); |
256 | | - if (ret != CIO_ERROR) { |
257 | | - printf("ISSUE DETECTED: Sync succeeded with NULL map pointer (inconsistent behavior)\n"); |
258 | | - printf("Expected: CIO_ERROR due to NULL map pointer\n"); |
| 235 | + /* Verify file is not mapped (using public API) */ |
| 236 | + TEST_CHECK(cio_chunk_is_up(chunk) == CIO_FALSE); |
| 237 | + printf("Verified: chunk is down (not mapped)\n"); |
| 238 | + |
| 239 | + /* Try to sync without mapping using public API */ |
| 240 | + /* On Windows, cio_file_native_sync (called by cio_file_sync) should check if mapped first */ |
| 241 | + printf("Attempting sync on unmapped file using cio_file_sync()...\n"); |
| 242 | + printf("cio_file_sync() internally calls cio_file_native_sync() which should validate mapping\n"); |
| 243 | + |
| 244 | + /* Use public API to sync - this internally calls cio_file_native_sync */ |
| 245 | + ret = cio_file_sync(chunk); |
| 246 | + printf("Result of sync without map: %d (expected: -1 for error)\n", ret); |
| 247 | + |
| 248 | + /* Expected: -1 (error) due to file not being mapped */ |
| 249 | + /* This TEST_CHECK verifies the fix prevents crashes */ |
| 250 | + TEST_CHECK(ret == -1); |
| 251 | + if (ret != -1) { |
| 252 | + printf("ISSUE DETECTED: Sync succeeded or returned unexpected value\n"); |
| 253 | + printf("Expected: -1 (error) due to file not being mapped\n"); |
259 | 254 | } |
260 | 255 |
|
261 | 256 | cio_chunk_close(chunk, CIO_FALSE); |
@@ -326,40 +321,58 @@ static void test_win32_map_size_mismatch() |
326 | 321 | cf = (struct cio_file *) chunk->backend; |
327 | 322 | TEST_CHECK(cf != NULL); |
328 | 323 |
|
| 324 | + /* Unmap if cio_chunk_open auto-mapped the file (using public API) */ |
| 325 | + if (cio_chunk_is_up(chunk) == CIO_TRUE) { |
| 326 | + ret = cio_file_down(chunk); |
| 327 | + TEST_CHECK(ret == 0); |
| 328 | + } |
| 329 | + |
| 330 | + /* Ensure file is still open */ |
| 331 | + if (!cio_file_native_is_open(cf)) { |
| 332 | + ret = cio_file_native_open(cf); |
| 333 | + TEST_CHECK(ret == CIO_OK); |
| 334 | + } |
| 335 | + |
329 | 336 | /* Try to map with a size larger than the file */ |
330 | 337 | map_size = file_size + 4096; /* Request 4KB more than file size */ |
331 | 338 | printf("Attempting to map %zu bytes (file is %zu bytes)\n", map_size, file_size); |
332 | 339 |
|
333 | | - /* Open file */ |
334 | | - ret = cio_file_native_open(cf); |
335 | | - TEST_CHECK(ret == CIO_OK); |
336 | | - |
337 | 340 | /* This is where the issue occurs: CreateFileMapping uses current file size (0,0), |
338 | 341 | * but MapViewOfFile tries to map a larger size */ |
339 | 342 | ret = cio_file_native_map(cf, map_size); |
340 | 343 | printf("Result of mapping %zu bytes to %zu byte file: %d\n", |
341 | 344 | map_size, file_size, ret); |
342 | 345 |
|
343 | | - /* The issue: CreateFileMapping is called with (0, 0) which uses file size, |
344 | | - * but MapViewOfFile requests map_size. This mismatch can cause issues. |
345 | | - * If mapping succeeds, alloc_size should match map_size, not file_size */ |
| 346 | + /* For read-only files, mapping beyond file size is not possible on Windows. |
| 347 | + * The mapping should be limited to file_size, and alloc_size should reflect |
| 348 | + * the actual mapped size (file_size), not the requested size (map_size). |
| 349 | + * This ensures consistency between CreateFileMappingA and MapViewOfFile sizes. */ |
346 | 350 | if (ret == CIO_OK) { |
347 | | - printf("WARNING: Mapping succeeded with size mismatch\n"); |
348 | | - printf("Expected alloc_size: %zu (map_size), file_size: %zu\n", map_size, file_size); |
| 351 | + printf("Mapping succeeded\n"); |
| 352 | + printf("Requested map_size: %zu, file_size: %zu\n", map_size, file_size); |
349 | 353 |
|
350 | | - /* Verify what was actually mapped - this may expose the issue */ |
351 | | - if (cio_file_native_is_mapped(cf)) { |
| 354 | + /* Verify what was actually mapped (using public API) */ |
| 355 | + if (cio_chunk_is_up(chunk) == CIO_TRUE) { |
352 | 356 | printf("File is mapped, alloc_size: %zu\n", cf->alloc_size); |
353 | | - /* This TEST_CHECK will highlight if alloc_size doesn't match requested map_size */ |
354 | | - /* Due to the bug, it may match file_size instead of map_size */ |
355 | | - TEST_CHECK(cf->alloc_size == map_size); |
| 357 | + |
| 358 | + /* For read-only files, alloc_size should match file_size (the actual mapped size), |
| 359 | + * not the requested map_size (which exceeds file size) */ |
| 360 | + /* This ensures consistency: CreateFileMappingA and MapViewOfFile both use actual_map_size */ |
| 361 | + TEST_CHECK(cf->alloc_size == file_size); |
| 362 | + |
| 363 | + if (cf->alloc_size != file_size) { |
| 364 | + printf("ISSUE DETECTED: alloc_size (%zu) doesn't match file_size (%zu)\n", |
| 365 | + cf->alloc_size, file_size); |
| 366 | + printf("For read-only files, mapping is limited to file_size\n"); |
| 367 | + } |
356 | 368 | } |
357 | 369 |
|
358 | 370 | ret = cio_file_native_unmap(cf); |
359 | 371 | TEST_CHECK(ret == CIO_OK); |
360 | 372 | } |
361 | 373 | else { |
362 | | - printf("Mapping failed when size mismatch occurs (may be correct behavior)\n"); |
| 374 | + printf("Mapping failed when size mismatch occurs\n"); |
| 375 | + /* For read-only files, this might be expected if map_size > file_size */ |
363 | 376 | } |
364 | 377 |
|
365 | 378 | cio_file_native_close(cf); |
@@ -405,26 +418,15 @@ static void test_win32_fd_check_inconsistency() |
405 | 418 | cf = (struct cio_file *) chunk->backend; |
406 | 419 | TEST_CHECK(cf != NULL); |
407 | 420 |
|
408 | | - /* Verify file is open using the proper macro */ |
409 | | - ret = cio_file_native_is_open(cf); |
410 | | - TEST_CHECK(ret == 1); |
411 | | - printf("cio_file_native_is_open(cf): %d\n", ret); |
412 | | - |
413 | | - /* Check cf->fd value on Windows (should be -1 or not set properly) */ |
414 | | - printf("cf->fd value: %d\n", cf->fd); |
415 | | - printf("cf->fd > 0 check: %d\n", (cf->fd > 0)); |
416 | | - printf("cio_file_native_is_open(cf): %d\n", cio_file_native_is_open(cf)); |
| 421 | + /* Verify file is open (using public API) */ |
| 422 | + ret = cio_chunk_is_up(chunk); |
| 423 | + TEST_CHECK(ret == CIO_TRUE); |
| 424 | + printf("cio_chunk_is_up(chunk): %d\n", ret); |
417 | 425 |
|
418 | | - /* This highlights that cf->fd > 0 doesn't work on Windows */ |
| 426 | + /* Check cf->fd value on Windows (internal check for documentation) */ |
419 | 427 | /* On Windows, cf->fd is typically -1, but the file is still open via backing_file */ |
420 | | - /* This TEST_CHECK will FAIL in CI, highlighting the inconsistency */ |
421 | | - /* cio_file.c line 804 uses cf->fd > 0 which is Unix-specific and doesn't work on Windows */ |
422 | | - TEST_CHECK((cf->fd > 0) == cio_file_native_is_open(cf)); |
423 | | - if ((cf->fd > 0) != cio_file_native_is_open(cf)) { |
424 | | - printf("ISSUE DETECTED: cf->fd check (%d) doesn't match cio_file_native_is_open (%d)\n", |
425 | | - (cf->fd > 0), cio_file_native_is_open(cf)); |
426 | | - printf("WARNING: cio_file.c line 804 uses cf->fd > 0 which is Unix-specific\n"); |
427 | | - } |
| 428 | + printf("cf->fd value: %d (internal, not used on Windows)\n", cf->fd); |
| 429 | + printf("Note: cio_file.c now uses cio_file_native_is_open() instead of cf->fd > 0\n"); |
428 | 430 |
|
429 | 431 | cio_chunk_close(chunk, CIO_FALSE); |
430 | 432 | cio_stream_delete(stream); |
|
0 commit comments