ThirteenAG
Game: True Crime New York City, don't know if that's important. With `Visual Studio 2022 (v143)` toolset, even compiled in VS2026 d3d8to9 works fine, only when switching to v145 toolset this happens on startup. ``` d3d8.dll!std::_Adl_verify_range<char const *,char const *>(const char * const & _First=0x05d8509a, const char * const & _Last=0x05d8507a) Line 1422 C++ Symbols loaded. d3d8.dll!std::copy<char const *,std::back_insert_iterator<std::string>>(const char * _First=0x05d8509a, const char * _Last=0x05d8507a, std::back_insert_iterator<std::string> _Dest={...}) Line 4972 C++ Symbols loaded. d3d8.dll!std::_Format_default<char const *,std::allocator<std::sub_match<char const *>>,char const *,std::back_insert_iterator<std::string>>(const std::match_results<char const *,std::allocator<std::sub_match<char const *>>> & _Match={...}, std::back_insert_iterator<std::string> _Out={...}, const char * _First=0x001adf15, const char * _Last=0x001adf15, std::regex_constants::match_flag_type __formal=match_default) Line 2259 C++ Symbols loaded. d3d8.dll!std::match_results<char const *,std::allocator<std::sub_match<char const *>>>::_Format1<std::back_insert_iterator<std::string>>(std::back_insert_iterator<std::string> _Out={...}, const char * _Fmt_begin=0x001adf10, const char * _Fmt_end=0x001adf15, std::regex_constants::match_flag_type _Flags=match_default) Line 1169 C++ Symbols loaded. d3d8.dll!std::_Regex_replace1<std::back_insert_iterator<std::string>,char const *,std::regex_traits<char>,char,std::char_traits<char>,std::allocator<char>>(std::back_insert_iterator<std::string> _Result={...}, const char * _First=0x05d85008, const char * _Last=0x05d850e7, const std::basic_regex<char,std::regex_traits<char>> & _Re={...}, const std::string & _Fmt={...}, std::regex_constants::match_flag_type _Flgs=match_default) Line 2481 C++ Symbols loaded. d3d8.dll!std::regex_replace<std::back_insert_iterator<std::string>,std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>>,std::regex_traits<char>,char,std::char_traits<char>,std::allocator<char>>(std::back_insert_iterator<std::string> _Result={...}, std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>> _First={...}, std::_String_const_iterator<std::_String_val<std::_Simple_types<char>>> _Last={...}, const std::basic_regex<char,std::regex_traits<char>> & _Re={...}, const std::string & _Fmt={...}, std::regex_constants::match_flag_type _Flgs=match_default) Line 2504 C++ Symbols loaded. d3d8.dll!std::regex_replace<std::regex_traits<char>,char,std::char_traits<char>,std::allocator<char>>(const std::string & _Str={...}, const std::basic_regex<char,std::regex_traits<char>> & _Re={...}, const char * _Ptr=0x5dbfb948, std::regex_constants::match_flag_type _Flgs=match_default) Line 2534 C++ Symbols loaded. > d3d8.dll!Direct3DDevice8::CreatePixelShader(const unsigned long * pFunction=0x00770790, unsigned long * pHandle=0x001afbd8) Line 1870 C++ Symbols loaded. True Crime New York City.exe!0065391c() Unknown Non-user code. Binary was not built with debug information ``` I didn't dig too much into it, apologies for that, but here's a summary of AI explanation and a possible solution: > The crash is caused by a known MSVC STL behavior: when a std::regex has two alternatives and one of them didn't match, the sub_match iterators for the unmatched group are in an invalid state. Passing them to copy triggers the "transposed pointer range" assertion. > The offending line: ```c std::regex_replace(SourceCode, std::regex("1?-(c[0-9])[\\._a-z0-9]*|(c[0-9])[\\.wxyz]*_[a-z0-9]*"), "-$1$2") ``` > • When alternative 1 matches, $2 is unmatched → invalid iterators > • When alternative 2 matches, $1 is unmatched → invalid iterators > Both cases then pass those bad iterators to copy → crash. > Fix: split into two separate replacements so each only references its own guaranteed-captured group: ```c // Make sure that the dest register is not already being used const std::string normalizedSourceCode = std::regex_replace( std::regex_replace(SourceCode, std::regex("1?-(c[0-9])[\\._a-z0-9]*"), "-$1"), std::regex("(c[0-9])[\\.wxyz]*_[a-z0-9]*"), "-$1"); std::string tmpLine = "\n" + normalizedSourceCode + "\n"; ``` > Each regex now only ever references $1, which is always captured when that pattern matches — no unmatched group is ever substituted. Content of a `SourceCode` variable during the crash: ``` ps_1_1 tex t0 tex t1 mul r0, v0, t0 mul r1, v1, t1 mul r0.xyz, r0, r0.w lrp r0.xyz, c0.w, r1, r0 + mul r0.w, 1-r0.w, 1-c0.w // approximately 6 instruction slots used (2 texture, 4 arithmetic) ```