| 44 | { |
| 45 | template <typename T> |
| 46 | std::string Join(const T& array, const std::string &delimiter) |
| 47 | { |
| 48 | // Calculate total size safely to avoid integer overflow and |
| 49 | // excessive reallocations. If the total size would overflow, |
| 50 | // return an empty string to fail safely. |
| 51 | using size_type = std::string::size_type; |
| 52 | size_type total = 0; |
| 53 | const size_type delim_size = static_cast<size_type>(delimiter.size()); |
| 54 | size_type count = 0; |
| 55 | |
| 56 | for (const auto &element : array) |
| 57 | { |
| 58 | const size_type elem_size = static_cast<size_type>(element.size()); |
| 59 | if (!SafeAdd<size_type>(total, elem_size, total)) |
| 60 | { |
| 61 | std::cout << "FAIL: SafeAdd overflow in element sum" << std::endl; |
| 62 | return std::string(); |
| 63 | } |
| 64 | ++count; |
| 65 | } |
| 66 | |
| 67 | std::cout << "After loop: count=" << count << " total=" << total << std::endl; |
| 68 | |
| 69 | if (count > 0 && count > 1) |
| 70 | { |
| 71 | // total delimiters = count - 1 (safe since count > 1) |
| 72 | const size_type delim_count = count - 1; |
| 73 | |
| 74 | size_type delim_total = 0; |
| 75 | if (!SafeMultiply<size_type>(delim_count, delim_size, delim_total)) |
| 76 | { |
| 77 | std::cout << "FAIL: SafeMultiply overflow in delimiter" << std::endl; |
| 78 | return std::string(); |
| 79 | } |
| 80 | |
| 81 | std::cout << "Delimiters: count=" << delim_count << " delim_size=" << delim_size << " delim_total=" << delim_total << std::endl; |
| 82 | |
| 83 | if (!SafeAdd<size_type>(total, delim_total, total)) |
| 84 | { |
| 85 | std::cout << "FAIL: SafeAdd overflow in total+delimiter" << std::endl; |
| 86 | return std::string(); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | std::cout << "Final total before reserve: " << total << std::endl; |
| 91 | |
| 92 | std::string res; |
| 93 | try |
| 94 | { |
| 95 | res.reserve(total); |
| 96 | } |
| 97 | catch (...) { |
| 98 | std::cout << "FAIL: reserve threw" << std::endl; |
| 99 | return std::string(); |
| 100 | } |
| 101 | |
| 102 | bool first = true; |
| 103 | for (const auto &element : array) |