Skip to content

Fix steam.exe crash (Access Violation 0xc0000005) during SteamVR exit - #3331

Closed
Roboct424 wants to merge 7 commits into
alvr-org:masterfrom
Roboct424:patch-3
Closed

Roboct424 wants to merge 7 commits into
alvr-org:masterfrom
Roboct424:patch-3

Conversation

@Roboct424

@Roboct424 Roboct424 commented Jul 2, 2026 •

Copy link
Copy Markdown

Fix steam.exe crash (Access Violation 0xc0000005) during SteamVR exit

Description

This PR addresses a severe race condition during the driver shutdown sequence on Windows environments. When SteamVR exits, it calls shutdown_driver() and immediately unloads driver_alvr_server.dll via FreeLibrary. However, background worker threads (specifically from the Tokio execution pool and asynchronous telemetry routines) often remain active for a few milliseconds longer. When they awake into unmapped memory addresses, a hard crash occurs inside steam.exe.

Changes made:

  • Fixed Clippy nested if warnings in alvr/server_openvr/src/lib.rs.
  • Wrapped raw pointer dereferencing (*return_code = 101) into an explicit unsafe block.
  • Fixed formatting to satisfy cargo fmt --check.
  • Documented code modifications in English.

⚠️ AI Disclaimer / Note to Reviewers

Please review this PR with extra care. This patch was authored with the assistance of Gemini LLM. I (the submitter) am not an expert in the ALVR codebase, but this solution successfully passes both compilation (cargo clippy --ci) and code formatting (cargo fmt).

Roboct424 added 5 commits July 2, 2026 14:08
О, классика! Ошибки синтаксиса в коде не дают Clippy (линтеру Rust) завершить проверку. Флаг `--ci` заставляет сборщик паниковать (`thread 'main' panicked...`) при наличии абсолютно любых предупреждений, расценивая их как критические ошибки сборки. Это стандартная практика на GitHub Actions, чтобы в репозиторий не попадал «грязный» код.

Смотри, сборка падает из-за трех предупреждений в файле `alvr\server_openvr\src\lib.rs`. Давай разберем каждое и починим их.

---

### Шаг 1: Неиспользуемый импорт (`unused_imports`)

В строке 34 импортируется `c_char`, который дальше нигде в коде не вызывается.
**Как исправить:** Открой файл `alvr\server_openvr\src\lib.rs`, найди строку 34 и просто удали `c_char` из списка импорта:

```rust
// Было:
ffi::{CString, OsStr, c_char, c_void},

// Стало:
ffi::{CString, OsStr, c_void},

```

---

### Шаг 2: Разыменование сырого указателя (`unsafe_op_in_unsafe_fn`)

В редакции Rust 2024 (и соответствующих свежих версиях компилятора) правила ужесточились: то, что функция помечена как `unsafe`, больше не делает её тело автоматически безопасным для работы с сырыми указателями. Разыменование `*return_code` в строке 678 обязано быть внутри явного блока `unsafe {}`.

**Как исправить:** Найди функцию `HmdDriverFactory` (примерно строка 669) и оберни разыменование в `unsafe`:

```rust
// Было:
if !return_code.is_null() {
    *return_code = 101; 
}

// Стало:
if !return_code.is_null() {
    unsafe {
        *return_code = 101; // Переносим под строгий контроль компилятора
    }
}

```

---

### Шаг 3: Схлопывание вложенных `if` (`collapsible_if`)

Линтер ругается на «лесенку» из `if let` и `if`. Их можно (и нужно для красоты) объединить в один логический блок с помощью оператора `&&`.

**Как исправить:** Замени конструкцию со строки 674 по 683 на лаконичный вариант:

```rust
// Было:
if let Ok(exe_path) = std::env::current_exe() {
    if let Some(file_name) = exe_path.file_name() {
        if file_name.to_string_lossy().to_lowercase() == "steam.exe" {
            // ...
        }
    }
}

// Стало:
if let Ok(exe_path) = std::env::current_exe()
    && let Some(file_name) = exe_path.file_name()
    && file_name.to_string_lossy().to_lowercase() == "steam.exe"
{
    if !return_code.is_null() {
        unsafe { *return_code = 101; }
    }
    return std::ptr::null_mut();
}

```

*(Примечание: Если компилятор начнет ругаться на то, что `&& let` в выражениях еще не стабилизирован в твоей версии Rust, можно использовать классический синтаксис `match` или вытащить условия через промежуточные переменные).*

---

Как только ты поправишь эти три места в `alvr\server_openvr\src\lib.rs` и перезапустишь `cargo xtask clippy --ci`, проверка должна успешно пройти зелёным цветом как на Windows, так и на Linux!
…Rust 2024 standards

NOTICE / DISCLAIMER:
This specific block of code was modified/generated with the assistance of an AI (Gemini LLM model). The human author contributor does not deeply understand the inner workings of this specific codebase and relies on the AI's patch to fix the underlying issue. Please review carefully during PR.
@Roboct424 Roboct424 changed the title Update lib.rs Fix steam.exe crash (Access Violation 0xc0000005) during SteamVR exit Jul 2, 2026
@Roboct424

Copy link
Copy Markdown
Author

I tested the branch on my system, and it launched without any issues. Steam no longer crashes when exiting SteamVR. As you can probably tell, I’m a complete novice at this kind of programming; I had help from an AI, and I’m hugely grateful to it. Unfortunately, though, the Desktop+ add-on still isn't working—its interface simply won't appear no matter what I do, yet it doesn't throw any errors. So, there's that...

@Roboct424

Copy link
Copy Markdown
Author

If you want to try out what I've built, here is a link to the dev versions for this branch: https://drive.google.com/drive/folders/19eZmMOXpU0NlYh6I9c--kzd3fGCWvKSw?usp=sharing

@zmerp

zmerp commented Jul 6, 2026 •

Copy link
Copy Markdown
Member

The fix is being addressed more extensively in #3333 and I'm inclined to accept that one as the fix. this PR though removes the conditional webserver_runtime destruction on linux. ideally we don't want to keep the cfg gate, but have you tested on linux?

@Roboct424

Copy link
Copy Markdown
Author

At the moment, I don't have the ability to test the build on Linux; I'll ask my colleagues to check it when they have time.

@besauce

besauce commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

The fix is being addressed more extensively in #3333 and I'm inclined to accept that one as the fix. this PR though removes the conditional webserver_runtime destruction on linux. ideally we don't want to keep the cfg gate, but have you tested on linux?

I think runtime.shutdown_timeout(Duration::from_secs(1)) instead of a plain drop would bound the wait and probably allow the gate removal. if anyone on linux hits the hang while testing the gate removal, sudo gdb -p $(pidof vrserver) -batch -ex "thread apply all bt" while it's hung should show the real cause. I can put up a PR with the shutdown_timeout approach if that's useful.

@zmerp

zmerp commented Jul 9, 2026

Copy link
Copy Markdown
Member

Sure thank you

@elektricM

elektricM commented Jul 19, 2026 •

Copy link
Copy Markdown

Setup: Arch, kernel 7.1.3, SteamVR 2.12.14 ("previous" branch, the one that still plays nice with ALVR), 7900 XTX. Built this branch plus a stock master build as control, registered each driver in turn and did repeated SteamVR launch/quit cycles.

Result: no hang. vrserver exits in ~1.1s with the runtime actually dropped, exactly the same as the control that leaks it. No leftover processes, no new coredumps. So whatever was bugged when that workaround was written doesn't seem to reproduce on a current stack, at least not in this scenario.

Caveats: no client was connected during these runs (headset off), so teardown mid-streaming is untested, and I haven't tried it on 2.15/2.16 yet. The steam.exe filename check in HmdDriverFactory is a no-op on Linux, as expected.

Two nits: if let Some(runtime) = self.webserver_runtime.take() { drop(runtime); } is just self.webserver_runtime.take(); with extra steps.

@besauce

besauce commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Sure thank you

Tested the gate removal on linux with a client connected and streaming, since that was the case nobody had covered yet.

Setup: CachyOS, RX 6900 XT, Mesa 26.1.5, SteamVR previous branch (buildid 22542555), Quest 3 over wifi. Built two streamers from the same tree, stock master e9b8e3a and master with just the gate removed (1 file, +1/-4). Timed from the shutdown request (POST /api/steamvr/shutdown, same thing the dashboard button sends) to vrserver exiting.

Control was 1.3-1.9s, gate removed was 1.4-2.3s over fifteen runs. I varied how I killed it: mid-stream, client closed on the headset first, quit from the SteamVR menu, quit a few seconds after the stream started, and a bunch of back to back cycles. Nothing hung, and no vrserver/vrcompositor/vrmonitor left behind in any run. I also made sure the test build actually lacked the gate (checked the diff, the two .so files differ, and vrserver.txt shows the right driver path loaded).

I tried to find out what the original hang was, but the gate came in as a direct commit (a80f384) with no issue or PR attached, so I can't find anything written down. The webserver it was written against was replaced in the axum migration (#3030) anyway. Do you know what it was guarding against?

So on this rig at least, the gate guards nothing. Happy to test the shutdown_timeout variant too if you'd rather keep a bound on it.

@zmerp

zmerp commented Jul 30, 2026

Copy link
Copy Markdown
Member

Great, seems we can just remove the cfg gate. I can merge a PR that isolates that change

@besauce

besauce commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Enjoy the vacation. ALVR will still be here, and I doubt anyone has ever came back from a vacation wishing they'd done a little extra before leaving instead of paced their departure.

l'll put one up shortly. It will be the single file change against current master, same tree I tested with.

@zmerp

zmerp commented Aug 12, 2026

Copy link
Copy Markdown
Member

This PR can be closed now

@zmerp zmerp closed this Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants