|
| 1 | +// Test case for Issue #169261: [libcxx] copy_file enters an infinite loop in a multithreaded environment |
| 2 | +// This test demonstrates the infinite loop bug in copy_file when called concurrently from multiple threads |
| 3 | +// when using copy_file_impl_copy_file_range (the count gets stuck at 0, causing an infinite loop) |
| 4 | + |
| 5 | +#include <filesystem> |
| 6 | +#include <thread> |
| 7 | +#include <vector> |
| 8 | +#include <fstream> |
| 9 | +#include <iostream> |
| 10 | +#include <chrono> |
| 11 | +#include <atomic> |
| 12 | + |
| 13 | +namespace fs = std::filesystem; |
| 14 | + |
| 15 | +// This test creates multiple threads that attempt to copy the same file concurrently |
| 16 | +// to different destinations to trigger the infinite loop condition |
| 17 | +void test_copy_file_multithreaded() { |
| 18 | + // Create a test source file |
| 19 | + fs::path src_file = "test_source.txt"; |
| 20 | + fs::path dest_dir = "test_dests"; |
| 21 | + |
| 22 | + // Cleanup from previous runs |
| 23 | + fs::remove_all(dest_dir); |
| 24 | + fs::create_directories(dest_dir); |
| 25 | + |
| 26 | + // Create source file with some content |
| 27 | + { |
| 28 | + std::ofstream out(src_file); |
| 29 | + out << "Test content for copy operation in multithreaded environment\n"; |
| 30 | + out << "This file tests the infinite loop issue reported in Issue #169261\n"; |
| 31 | + for (int i = 0; i < 100; ++i) { |
| 32 | + out << "Line " << i << ": Lorem ipsum dolor sit amet\n"; |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + // Test: Create multiple threads that copy the file concurrently |
| 37 | + std::vector<std::thread> threads; |
| 38 | + std::atomic<int> success_count(0); |
| 39 | + std::atomic<int> error_count(0); |
| 40 | + |
| 41 | + auto copy_worker = [&](int thread_id) { |
| 42 | + try { |
| 43 | + fs::path dest = dest_dir / ("copy_" + std::to_string(thread_id) + ".txt"); |
| 44 | + // Add timeout mechanism to detect infinite loop (hang would indicate bug) |
| 45 | + std::cout << "Thread " << thread_id << ": Starting copy operation\n"; |
| 46 | + fs::copy_file(src_file, dest); |
| 47 | + std::cout << "Thread " << thread_id << ": Copy completed successfully\n"; |
| 48 | + success_count++; |
| 49 | + } catch (const std::exception& e) { |
| 50 | + std::cout << "Thread " << thread_id << ": Error - " << e.what() << "\n"; |
| 51 | + error_count++; |
| 52 | + } |
| 53 | + }; |
| 54 | + |
| 55 | + // Spawn multiple threads |
| 56 | + for (int i = 0; i < 4; ++i) { |
| 57 | + threads.emplace_back(copy_worker, i); |
| 58 | + } |
| 59 | + |
| 60 | + // Wait for all threads with timeout |
| 61 | + for (auto& thread : threads) { |
| 62 | + thread.join(); |
| 63 | + } |
| 64 | + |
| 65 | + std::cout << "Test completed: Success=" << success_count << " Errors=" << error_count << "\n"; |
| 66 | + |
| 67 | + // Verify all files were created |
| 68 | + int created_files = 0; |
| 69 | + for (const auto& entry : fs::directory_iterator(dest_dir)) { |
| 70 | + if (entry.is_regular_file()) { |
| 71 | + created_files++; |
| 72 | + } |
| 73 | + } |
| 74 | + std::cout << "Files created in destination: " << created_files << "\n"; |
| 75 | + |
| 76 | + // Cleanup |
| 77 | + fs::remove(src_file); |
| 78 | + fs::remove_all(dest_dir); |
| 79 | +} |
| 80 | + |
| 81 | +int main() { |
| 82 | + std::cout << "Testing copy_file in multithreaded environment (Issue #169261)\n"; |
| 83 | + test_copy_file_multithreaded(); |
| 84 | + std::cout << "Test finished\n"; |
| 85 | + return 0; |
| 86 | +} |
0 commit comments