---
title: "修复了 Mac 版《文明5》中 AI 夺回首都时导致的崩溃"
url: "https://reamcp.dev/zh-cn/cases/fixed-the-mac-civ-v-crash-when-an-ai-recaptures-its-capital-c10faf"
source: "https://github.com/jtutlis/civ5-mac-capital-crash-fix"
source_type: "github"
repo: "https://github.com/jtutlis/civ5-mac-capital-crash-fix"
author: "jtutlis1"
author_handle: "jtutlis1"
stars: 0
category: "补丁与修复"
categories: ["patches-fixes"]
tags: ["civilization-v", "crash-analysis", "game-binary-patching", "macos", "reverse-engineering"]
added: "2026-10-13T03:39:22.266Z"
updated: "2026-10-11T19:31:19Z"
locale: "zh-cn"
content_locale: "zh-cn"
---

# 修复了 Mac 版《文明5》中 AI 夺回首都时导致的崩溃

一位《文明5》玩家使用 Claude + REA 诊断了 macOS 上反复出现的崩溃问题，该崩溃在 AI 夺回其首都时触发，并发布了一个二进制补丁来修复它。

## Description

作者描述了 Mac 版《文明5》中一个长期存在的崩溃问题，大约每十局游戏就会发生一次，发生在某个文明夺回其首都时。在未能找到现有修复方法后，他们使用 Claude 结合 REA 来追踪根本原因，并制作了一个补丁，发布在 https://github.com/jtutlis/civ5-mac-capital-crash-fix。该修复通过修补游戏二进制文件来应用，而不是作为模组，因为模组会禁用成就。

## Original README

# Civ V Mac: capital recapture crash fix

A binary patch for **Sid Meier's Civilization V on macOS** (Steam, Brave New World) that fixes a crash
when a civilization recaptures its original capital.

> Not affiliated with Firaxis, Aspyr or 2K. This repository contains no game files; the patch
> modifies your own installed copy and keeps a backup.

## The bug

In Brave New World games the game crashes to desktop right after a
civilization takes back its original capital. It happens whenever no single team holds the most
original capitals at that moment, for example when every civ holds just its own capital.

If your crash report (`~/Library/Logs/DiagnosticReports/Civilization V-*.ips`) looks like this, this is
your bug:

```
Exception Type:    EXC_BAD_ACCESS (SIGSEGV)
Thread N Crashed:: WinMain (WinID 2)
0   ???                                      0x...      ???
1   libCvGameCoreDLL_Expansion2_DLL.dylib    0x...      0x... + 3013620
2   libCvGameCoreDLL_Expansion2_DLL.dylib    0x...      0x... + 2995429
```

## Requirements

- macOS, Steam version of Civilization V with Brave New World. Tested on Apple silicon (the game runs
  under Rosetta) on macOS 26.4.
- The supported game core build:
  `libCvGameCoreDLL_Expansion2_DLL.dylib` with sha256
  `0da6a5ffc283c3f147b20a7ec426e4ed85a6838ab891faf61b50af4e25c4a09c`.
  The script checks this and refuses to patch any other version.

Only built-in macOS tools are used (`bash`, `dd`, `od`, `shasum`, `codesign`).

## Install

1. Quit Civilization V.
2. Download this repository (green **Code** button → **Download ZIP**, or `git clone`) and open
   Terminal in its folder.
3. Run:

   ```sh
   ./patch.sh apply
   ```

Check the state at any time with `./patch.sh status`.

If your Steam library is not in the default location, point the script at the game core:

```sh
CIV5_GAMECORE="/path/to/Civilization V.app/Contents/MacOS/libCvGameCoreDLL_Expansion2_DLL.dylib" ./patch.sh apply
```

**After a game update or Steam's "Verify integrity of game files"**, Steam restores the original
file. Run `./patch.sh apply` again.

## Uninstall

```sh
./patch.sh revert
```

or use Steam's **Properties → Installed Files → Verify integrity of game files**.

## FAQ

**Can this get me banned?** Civilization V does not use Valve Anti-Cheat (VAC), and Firaxis
publishes the game core's source so players can replace it. Mods such as the Community Patch
(Vox Populi) have replaced this library for years.

**Does it disable achievements?** No. It doesn't use the in-game mod system, which is what turns
achievements off.

**Multiplayer?** Everyone in a multiplayer game should run the same game core. Mixing patched and
unpatched players is untested and may cause desyncs.

**Windows?** This patch only targets the macOS build.

## How it works

The crash is in `CvPlayer::SetHasLostCapital(bool bValue, PlayerTypes eConqueror)` (address
`0x2de2d0` in the stripped library). When a capital changes hands, the function counts original
capitals per team to find which team is "winning", which the notification text mentions. If no
single team leads, the winning team is `NO_TEAM` (`-1`).

When building the "you recovered your capital" notification for the civ that just regained its
capital, the code calls `GET_TEAM(eMyTeam).isHasMet(eWinningTeam)` without checking for `NO_TEAM`.
`isHasMet` is `return m_abHasMet[eIndex];`, compiled as:

```asm
movl   %esi, %eax                ; zero-extends -1 to 0x00000000ffffffff
movb   0x738(%rdi,%rax), %al     ; reads ~4 GB past the CvTeam object -> SIGSEGV
```

In 32-bit builds this would read one byte before the array and carry on. The 64-bit Mac build
reads unmapped memory and crashes. The "lost capital" path and the notifications sent to other
players already check for `NO_TEAM`; this one path doesn't.

The patch adds that check, jumping to the code the function already has for the no-winner case
(the plain "you recovered your capital" text). It needs 10 bytes, taken from a redundant bounds
check on the player's own ID, which is always valid:

```asm
; before (0x2dfbba)                       ; after (0x2dfbba)
movq   -0x38(%rbp), %rax                  cmpl   $-0x1, -0x50(%rbp)   ; eWinningTeam == NO_TEAM?
movslq (%rax), %rax                       je     0x2dfca8             ; no-winner notification
movl   $0xffffffff, %ecx                  movq   -0x38(%rbp), %rax
cmpq   $0x3f, %rax                        movslq (%rax), %rax
ja     0x2dfbd6                           movq   -0x60(%rbp), %rcx
movq   -0x60(%rbp), %rcx                  movq   (%rcx), %rcx
movq   (%rcx), %rcx                       movl   (%rcx,%rax,4), %ecx
movl   (%rcx,%rax,4), %ecx                nop
```

28 bytes change in total. Editing the code invalidates the library's ad hoc code signature, so the
script re-signs it ad hoc (`codesign --sign -`), which is how it was originally signed.

## Reproducing the crash

`test/` contains a small Lua mod that stages the crash on turn 2: one AI captures another AI's
original capital, and the owner immediately recaptures it.

```sh
test/civ5test.sh setup       # install the test mod, enable Lua logging
./patch.sh revert            # optional: start with the original game core
```

1. Launch Civ V → **Mods** → enable **Capital Recapture Test** → **Single Player** → **Set Up Game**
   with at least two AI civs.
2. Press **End Turn** until turn 2.
   - Original game core: the game crashes.
   - Patched: notifications show an unmet player losing and then regaining its capital, and the
     game keeps running.
3. To rerun quickly, load the turn 1 autosave from the Mods menu and press **End Turn**.

```sh
test/civ5test.sh result      # test log lines (Lua.log is written on exit) and new crash reports
./patch.sh apply             # switch to the patched game core
test/civ5test.sh teardown    # remove the mod and restore the logging setting
```

Achievements are disabled while the test mod is active; run `teardown` when you're done.

## Credits

Found with [REA](https://github.com/morluto/rea) and Hopper Disassembler, using a crash report to
locate the faulting instruction.

## License

MIT. See [LICENSE](LICENSE).
