==14392==ERROR: AddressSanitizer: stack-use-after-...

생성일: 2026년 4월 22일

답변에 사용된 모델 GPT-5.4 Thinking by Chat01

질문

==14392==ERROR: AddressSanitizer: stack-use-after-scope on address 0x00f55fdfd810 at pc 0x7ffce6529b16 bp 0x00f55fdfd7f0 sp 0x00f55fdfd7f8
WRITE of size 8 at 0x00f55fdfd810 thread T0
#0 0x7ffce6529b15 in std::basic_string<wchar_t, struct std::char_traits<wchar_t>, class std::allocator<wchar_t>>::max_size(void) const C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.50.35717\include\xstring:2288
#1 0x7ffce631e059 in std::basic_string<wchar_t, struct std::char_traits<wchar_t>, class std::allocator<wchar_t>>::_Construct<1, wchar_t const *>(wchar_t const *const, unsigned __int64) C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.50.35717\include\xstring:931
#2 0x7ffce64ba42a in std::basic_string<wchar_t, struct std::char_traits<wchar_t>, class std::allocator<wchar_t>>::basic_string<wchar_t, struct std::char_traits<wchar_t>, class std::allocator<wchar_t>>(wchar_t const *const) C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.50.35717\include\xstring:819
#3 0x7ffce653a0c4 in AgpInit E:\TEST_AGP\TEST_FUNC\TEST_FUNC.cpp:4730
#4 0x7ffceab527dc (<unknown module>)

Address 0x00f55fdfd810 is located in stack of thread T0
SUMMARY: AddressSanitizer: stack-use-after-scope C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\MSVC\14.50.35717\include\xstring:2288 in std::basic_string<wchar_t, struct std::char_traits<wchar_t>, class std::allocator<wchar_t>>::max_size(void) const
Shadow bytes around the buggy address:
0x00f55fdfd580: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f55fdfd600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f55fdfd680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f55fdfd700: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f55fdfd780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x00f55fdfd800: 00 00[f8]f1 f1 f1 00 f2 f8 f2 f8 f2 f8 f3 f3 f3
0x00f55fdfd880: f3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f55fdfd900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f55fdfd980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00f55fdfda00: f1 f1 f1 f1 01 f2 01 f2 f8 f2 00 f2 00 f2 f8 f3
0x00f55fdfda80: f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb - получаю ошибку, где - extern "C" _declspec(dllexport) int AgpInit() noexcept {
g_env = new boost::mpi::environment();
g_world = new boost::mpi::communicator();
MM_SET_FLUSH_ZERO_MODE(MM_FLUSH_ZERO_ON);
MM_SET_DENORMALS_ZERO_MODE(MM_DENORMALS_ZERO_ON);
const int rank = g_world->rank();
if (rank == 0) {
wchar_t buf[MAX_PATH]{};
GetModuleFileNameW(nullptr, buf, MAX_PATH);
std::wstring ws(buf);
const auto pos = ws.find_last_of(L"\/");
ws.resize(pos);
const int n = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, nullptr, 0, nullptr, nullptr);
g_exeDirCache.resize(static_cast<size_t>(n));
WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, g_exeDirCache.data(), n, nullptr, nullptr);
g_exeDirCache.pop_back();
g_pyInterpreter = new pybind11::scoped_interpreter{};
pybind11::module
sys = pybind11::module
::import("sys");
pybind11::list path = sys.attr("path");
const std::string& exeDir = g_exeDirCache;
path.attr("insert")(0, pybind11::str(exeDir + "\env\Lib\site-packages"));
path.attr("insert")(0, pybind11::str(exeDir + "\env\Scripts"));
path.attr("insert")(0, pybind11::str(exeDir + "\env"));
path.attr("append")(pybind11::str(exeDir));
pybind11::module
::import("warnings").attr("filterwarnings")("ignore");
g_pyOptimizerBridge = new pybind11::module
(pybind11::module
::import("optimizer_bridge"));
}
return rank;
}, а строка 4730 это std::wstring ws(buf);

사고

Смотрю на стек и сам фрагмент. Уже видно важную вещь: строка std::wstring ws(buf); почти наверняка не первопричина, а место, где повреждение проявилось.

Thought for 31s

답변

Нет, проблема, скорее всего, не в std::wstring ws(buf); самой по себе.

По вашему ASan-логу важнее вот это:

  • stack-use-after-scope
  • адрес помечен как f8 = Stack use after scope
  • падение происходит внутри конструктора std::wstring, но это часто означает, что к моменту создания ws уже испорчен стек или используется ссылка/указатель на локальный объект, который уже умер.

То есть строка

cpp
std::wstring ws(buf);

обычно здесь жертва, а не источник.

Почему именно так

Если бы проблема была в buf, вы бы чаще увидели что-то вроде:

  • stack-buffer-overflow
  • invalid read
  • heap-buffer-overflow

А тут ASan говорит, что идет запись в область стека, которая уже считается вышедшей из scope. Это очень похоже на один из сценариев:

  1. Где-то раньше сохранили указатель/ссылку на локальную переменную
  2. Повредили стек до этой строки
  3. Есть ложное срабатывание/артефакт ASan + оптимизации + MSVC, но это реже, чем реальная порча стека

Что в вашем коде стоит проверить сразу

1. GetModuleFileNameW и нуль-терминатор

Вот это место небезопасно:

cpp
wchar_t buf[MAX_PATH]{}; GetModuleFileNameW(nullptr, buf, MAX_PATH); std::wstring ws(buf);

GetModuleFileNameW не гарантирует нуль-терминатор, если путь был обрезан по MAX_PATH.

Надо делать так:

cpp
wchar_t buf[MAX_PATH]{}; DWORD len = GetModuleFileNameW(nullptr, buf, MAX_PATH); if (len == 0 || len >= MAX_PATH) { return -1; // или ваш код ошибки } std::wstring ws(buf, len);

Это не очень похоже на ваш stack-use-after-scope, но это все равно баг, который надо исправить.


2. ws.resize(pos);

Если find_last_of не найдет \\ или /, то pos == std::wstring::npos, и resize(pos) — это уже UB/исключение.

Надо:

cpp
const auto pos = ws.find_last_of(L"\\/"); if (pos == std::wstring::npos) { return -2; } ws.resize(pos);

3. Глобальные/статические ссылки на временные или локальные объекты

Вот это безопасно:

cpp
const std::string& exeDir = g_exeDirCache;

потому что g_exeDirCache — не локальная переменная.

Но очень похоже, что вокруг AgpInit или до него есть код, где:

  • сохраняется wchar_t* на локальный буфер
  • сохраняется std::wstring_view / std::string_view на временную строку
  • сохраняется ссылка на локальный std::string / std::wstring
  • где-то есть callback/lambda, захватившая локальную переменную по ссылке

И потом это бьет стек, а проявляется уже на std::wstring ws(buf).


Самый вероятный вывод по вашему логу

С высокой вероятностью:

ошибка находится не на строке 4730, а раньше — в коде, который повредил стек или оставил висячую ссылку на локальный объект.


Как сузить причину быстро

Перепишите этот кусок в безопасном виде

cpp
extern "C" __declspec(dllexport) int AgpInit() noexcept { g_env = new boost::mpi::environment(); g_world = new boost::mpi::communicator(); _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); const int rank = g_world->rank(); if (rank == 0) { wchar_t buf[MAX_PATH] = {}; DWORD len = GetModuleFileNameW(nullptr, buf, MAX_PATH); if (len == 0 || len >= MAX_PATH) { return -1; } std::wstring ws(buf, len); const auto pos = ws.find_last_of(L"\\/"); if (pos == std::wstring::npos) { return -2; } ws.resize(pos); const int n = WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, nullptr, 0, nullptr, nullptr); if (n <= 0) { return -3; } g_exeDirCache.resize(static_cast<size_t>(n - 1)); WideCharToMultiByte(CP_UTF8, 0, ws.c_str(), -1, g_exeDirCache.data(), n, nullptr, nullptr); g_pyInterpreter = new pybind11::scoped_interpreter{}; pybind11::module_ sys = pybind11::module_::import("sys"); pybind11::list path = sys.attr("path"); const std::string& exeDir = g_exeDirCache; path.attr("insert")(0, pybind11::str(exeDir + "\\env\\Lib\\site-packages")); path.attr("insert")(0, pybind11::str(exeDir + "\\env\\Scripts")); path.attr("insert")(0, pybind11::str(exeDir + "\\env")); path.attr("append")(pybind11::str(exeDir)); pybind11::module_::import("warnings").attr("filterwarnings")("ignore"); g_pyOptimizerBridge = new pybind11::module_(pybind11::module_::import("optimizer_bridge")); } return rank; }

Еще один важный момент: noexcept

У вас функция объявлена как:

cpp
extern "C" __declspec(dllexport) int AgpInit() noexcept

Но внутри вызывается куча вещей, которые могут бросить исключение:

  • new
  • std::wstring
  • std::string::resize
  • pybind11::module_::import
  • pybind11::scoped_interpreter

Если там вылетает исключение, при noexcept вы получите std::terminate, и отладка будет сильно путаться.

На время диагностики лучше убрать noexcept или хотя бы обернуть всё в try/catch.

Например:

cpp
extern "C" __declspec(dllexport) int AgpInit() { try { ... } catch (const std::exception& e) { return -100; } catch (...) { return -101; } }

Что я бы проверил прямо сейчас

  1. Все string_view / wstring_view
  2. Все глобальные const char* / const wchar_t*
  3. Все лямбды с захватом по ссылке
  4. Все места, где возвращается c_str() от временной строки
  5. Всё, что выполняется перед AgpInit и могло испортить стек

Особенно ищите такое:

cpp
const wchar_t* p = someLocalWstring.c_str(); // плохо, если someLocalWstring потом умирает std::wstring_view v = local_wstring; // плохо, если view живет дольше строки global_ref = local_string; // плохо, если это ссылка

Итог

По вашему логу:

  • ASan не указывает, что ошибка в buf
  • строка std::wstring ws(buf); — скорее место проявления
  • вероятная причина — висячая ссылка/указатель на локальный объект или повреждение стека раньше
  • сам код при этом тоже стоит поправить:
    • использовать длину из GetModuleFileNameW
    • проверить npos
    • убрать noexcept на время диагностики

Если хотите, я могу дальше помочь точечно: разберу весь AgpInit построчно и покажу, какие места в нём реально опасны, а какие нет.

이 Q&A 공유하기