> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XBOX 上的 Address Sanitizer 支持

> XBOX 上的 Address Sanitizer 支持

与大多数 C++ 程序一样，游戏也可能出现一类影响程序正确性和稳定性的 bug，因此从 Visual Studio 2022 起，Microsoft C/C++ 编译器 (MSVC) 与 IDE 开始支持 AddressSanitizer (ASan) 技术。这是一种编译器与运行时技术，可零误报地暴露许多难以发现的 bug，例如：

* alloc/dealloc 不匹配以及 new/delete 类型不匹配
* 分配对堆过大
* calloc 溢出与 alloca 溢出
* 双重释放 (double free) 与释放后使用 (use after free)
* 全局变量溢出
* 堆缓冲区溢出
* 对齐值的无效对齐
* memcpy 与 strncat 参数重叠
* 栈缓冲区上溢与下溢
* return 后使用栈以及 scope 结束后使用
* 内存中毒后使用

有关 ASan 的更多信息可在 Visual Studio 页面找到：[AddressSanitizer](https://learn.microsoft.com/cpp/sanitizers/asan)（Microsoft Docs）。

## 在编译器中启用 ASan

Address Sanitizer 已集成到 Visual Studio 项目系统、CMake 构建系统和 IDE 中。项目可以通过额外的编译器选项 *`/fsanitize=address`* 或在 Visual Studio 中设置项目属性来启用 AddressSanitizer：

<img src="https://mintcdn.com/microsoft-4404708b/ktEik-YaZoen6Rhy/images/gdk/tools/Address_Sanitizer_Project_Props.png?fit=max&auto=format&n=ktEik-YaZoen6Rhy&q=85&s=1717f26cc38c6cfdc96e683cb32752c0" alt="Visual Studio 中的 ASan 编译器选项" width="696" height="425" data-path="images/gdk/tools/Address_Sanitizer_Project_Props.png" />

<Note>此选项与所有 x64 优化等级和配置兼容。然而，它与 `edit-and-continue`、`incremental linking` 和 `/RTC` **不兼容**，在使用 ASan 编译之前必须禁用这些选项。</Note>

启用 ASan 时需要将一个额外的库链接到你的代码中。这个引用会由构建系统自动添加。这还要求你在项目的 ***Linker > General*** 下设置 “Additional Library Directories”。请确保 `$(VC_LibraryPath_VC_x64)` 值是列表中的最后一项，以防止它被用于其他库，如下所示：

<img src="https://mintcdn.com/microsoft-4404708b/ktEik-YaZoen6Rhy/images/gdk/tools/Address_Sanitizer_Linker_Options.png?fit=max&auto=format&n=ktEik-YaZoen6Rhy&q=85&s=8f81ff7561ee160e16164518191f789b" alt="Visual Studio 中的 ASan 链接器选项" width="752" height="128" data-path="images/gdk/tools/Address_Sanitizer_Linker_Options.png" />

## ASan 运行时要求

当游戏在启用 ASan 的情况下构建时，需要在运行时提供一个额外的 DLL，该 DLL 启用相关功能。默认情况下，当在编译器中启用 ASan 时，它会将此 DLL 复制到项目的输出目录中，然后应与可执行文件一起部署到主机上。

如需要，可以在 Visual Studio 的 `$(VC_ExecutablePath_x64)` 目录中手动找到这些 DLL。根据构建版本，XBOX 需要以下两者之一：

| DLL Filename                           | Build Type     |
| -------------------------------------- | -------------- |
| `clang_rt.asan_dbg_dynamic-x86_64.dll` | Debug builds   |
| `clang_rt.asan_dynamic-x86_64.dll`     | Release builds |

## 运行时调试器支持

在附加调试器的情况下运行启用 ASan 的游戏时，如果发现错误，它会中断进入调试器并显示详细报告，让你能确定错误发生的位置。

但如果你在没有附加调试器的情况下运行（例如在自动化测试框架中），则错误信息会显示在标准输出上，游戏会终止。这可能有所帮助，但你可能需要更多状态信息来找到崩溃的根本原因，这就是 Crash Dump 支持发挥作用的地方。

<Note>如果你在没有附加调试器的情况下运行，且需要在此时解析符号，则需要将 `llvm-symbolizer.exe` 文件与游戏 EXE 一起部署。此文件与上文列出的 ASan 运行时 DLL 位于同一位置。</Note>

## 运行时 Crash Dump 支持

从 Visual Studio 16.9.8 或 16.10.2 起，可以配置 ASan 以保存包含与错误关联的元数据的崩溃转储文件。Visual Studio 中的调试器可以解析该转储文件中保存的元数据，为崩溃提供更多上下文。你可以按构建配置崩溃转储保存，存储这些二进制产物，然后在 IDE 中通过合适的源索引查看它们。

Crash Dump 文档可在此处找到：
[Configuring Crash Dumps](https://learn.microsoft.com/cpp/sanitizers/asan-offline-crash-dumps)（Microsoft Docs）。

但上述链接的方案需要设置环境变量，而 XBOX 上不支持此操作，因此实现了另一种方法。要为你的 XBOX title 添加 Crash Dump 支持，只需定义一个回调函数，向 ASan 提供所需的崩溃转储文件名信息即可，下面给出了三个示例。

<Note>为了遵循 Visual Studio IDE 约定，文件名通常以 ***.dmp*** 结尾。</Note>

```c++ theme={null}
// 1. Use a hardcoded dump name
extern "C" const wchar_t* __vcasan_save_dumps()
{
    return L"myCrashDump.dmp";
}

// 2. Programmatically build the dump name
extern "C" const wchar_t* __vcasan_save_dumps()
{
    return TestFramework.buildName + TestFramework.buildInfo + TestFramework.dateTime;
}

// 3. You can conditionally choose NOT to collect a crash dump
extern "C" const wchar_t* __vcasan_save_dumps()
{
    // Choose to create a crash dump based on a runtime flag
    if ( gCollectCrashDumps )
    {
        return L"myCrashDump.dmp";
    }
    else
    {
        // Returning NULL stops ASan creating a crash dump
        return NULL;
    };
}
```

对该函数返回的名称没有特定要求，但它必须是运行代码所在目标设备上的一个有效文件路径。例如，将崩溃转储写入主机上的 D: 盘，可以在开发期间轻松找到并取出它们。

我们还添加了修改所生成 crash dump 类型的能力。在有些场景下，简单的 “Triage” dump 足以查看进程失败位置的调用堆栈；但对于某些问题，你可能需要问题发生时的周围内存信息。为此，我们提供了三种 XBOX 平台支持的可配置 crash dump 类型，与主机及 xbWatson 生成的 crash dump 类型相匹配。

<Note>与前一个函数一样，此重写在 XBOX 上是**可选的**，但如果你希望在没有附加调试器的情况下使用 crash dump 来收集 ASan 信息，则强烈推荐使用。如果你提供了转储文件名但**未**提供 dumptype 重写，则将无法在 XBOX 上生成有效的崩溃转储。</Note>

该回调返回一个数字，表示所需的 dump 类型。有效类型如下例所示：

```c++ theme={null}
extern "C" const signed int __vcasan_override_dumptype()
{
    // The current valid values are:
    // 0 : Triage Dump
    // 1 : Mini Dump
    // 2 : Heap Dump
    // Values outside this range are defaulted to 2 (Full Heap)

    // This example uses Heap Dumps which give the most information
    return 2;
}
```

## 示例 ASan 代码

以下代码演示了这些函数可以多么容易地添加到现有代码库中，并根据需要进行调整：

```c++ theme={null}
#include <cstdio>

extern "C" const wchar_t* __vcasan_save_dumps()
{
    // Specify dump filename
    return L"myCrashDump.dmp";
}

extern "C" const signed int __vcasan_override_dumptype()
{
    // Full heap dump requested
    return 2;
}

static const int arraySize = 8;
static int asanArray[arraySize];
static int asanAccumulator = 0;

int main()
{
    // ASan should use the callback functions that we have provided
    for (int loop = 0; loop <= arraySize; loop++)
    {
        // We don't really care about accumulating the values
        // We just want to access outside the array causing an ASan error
        asanAccumulator += asanArray[loop];
    }

    // If we get here, we have failed as ASan should have caught the error above
    printf("fail");

    return 0;
}
```

通过以下命令行编译该代码：

```c++ theme={null}
cl /nologo /fsanitize=address /Zi ASanTest.cpp
```

执行时，此代码将抛出一个 ASan 异常，并按上述函数所指定生成 crash dump。你可以将这些函数集成到现有代码库中，在启用 ASan 时按需生成 crash dump。

## 已知问题

* Visual Studio 2019 (16.11) 的 ASan 与 Game OS 不兼容。

* ASan DLL 与 Game OS 不兼容，17.12 和 17.13 的初始版本会加载失败。此问题已在 17.12.6 和 17.13.3 中修复。

* Visual Studio 2022 中导致 Game OS 启动时崩溃的 ASan 支持回归问题，已在 17.14.29 中修复；Visual Studio 2026 中在 18.4.1 中修复。

* 在 XBOX 上使用调试器运行时，会定期发出以下异常消息，可安全忽略：

```
Exception thrown at 0x00007FF8FCAAFCF6 (clang_rt.asan_dynamic-x86_64.dll) in game.exe: 0xE0736171: Access violation reading location 0x000017FF1F9E1250.
```


## Related topics

- [主机上的 Developer Home (Dev Home)](/zh-CN/tools/tools-console/devhome/devhome.md)
- [Visual Studio](/zh-CN/tools/tools-console/visualstudio/index.md)
- [GetGPUVirtualAddress](/zh-CN/reference/graphics/d3d12/interfaces/id3d12resource/methods/id3d12resource_getgpuvirtualaddress_public.md)
- [在 Visual Studio 中远程调试 Windows 设备上的 PC 项目](/zh-CN/tools/tools-pc/visualstudio/gr-vs-debugging-with-visualstudio-remote-windows.md)
- [ApuIsVirtualAddressValid](/zh-CN/reference/audio/apu/functions/apuisvirtualaddressvalid.md)
