matrix-org / matrix-org/matrix-js-sdk
Null pointer crash in receiveSyncChanges via DehydratedDevices
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.2k
- Forks
- 704
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 40
Description
Hello, I am not sure if this is the right place for creating this issue, or if it's an existing issue that's fixed.
## Description
`OlmMachine.receiveSyncChanges` crashes with `"null pointer passed to rust"` when processing device list sync data that involves DehydratedDevices. The crash occurs because the `DehydratedDevices` struct accesses a `Device` reference that is null.
This is unrecoverable — it kills the WASM OlmMachine and prevents all further crypto operations, including room key delivery for message decryption.
## Environment
- `matrix-js-sdk`: 40.1.0
- `@matrix-org/matrix-sdk-crypto-wasm`: ^17.0.0 (resolved via matrix-js-sdk dependency)
- Browser: Chrome 133 (macOS)
- Trigger: Normal `/sync` response processing with bridged rooms (mautrix bridges)
## Steps to Reproduce
1. Initialize MatrixClient with Rust crypto (`initRustCrypto`)
2. Start sync loop
3. Receive a `/sync` response that includes `device_lists` updates
4. `processDeviceLists` calls `receiveSyncChanges({ devices })`
5. The WASM `olmMachine.receiveSyncChanges()` crashes with: `Error: null pointer passed to rust`
## Stack Trace
```
Error: null pointer passed to rust
at OlmMachine.receiveSyncChanges (matrix_sdk_crypto_wasm_bg.wasm)
at RustCrypto.receiveSyncChanges (rust-crypto.js)
```
## Impact
- **Critical**: The crash kills the OlmMachine entirely — no further crypto operations are possible
- All message decryption stops after the crash
- Room key shares delivered via to-device messages are also lost if a catch-all handler returns `[]`
## Current Workaround
We wrap `receiveSyncChanges` to catch the null pointer error and retry without the `devices` parameter, so that to-device events (key shares) are still processed while the problematic device list processing is skipped:
```javascript
const original = crypto.receiveSyncChanges.bind(crypto);
crypto.receiveSyncChanges = async (args) => {
try {
return await original(args);
} catch (err) {
if (err.message?.includes("null pointer")) {
// Retry without device lists to preserve key share processing
const { devices, ...stripped } = args;
return await original(stripped);
}
throw err;
}
};
```
## Expected Behavior
`receiveSyncChanges` should handle null/missing Device references in DehydratedDevices gracefully instead of crashing.
## Additional Context
The crash appears related to the DehydratedDevices struct accessing a Device that was never initialized. This may be triggered by specific device list configurations from mautrix bridge bots.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at processDeviceLists and RustCrypto.receiveSyncChanges in rust-crypto.js, then inspect the OlmMachine.receiveSyncChanges entry point and the DehydratedDevices handling described in the report. Reproduce with a /sync response containing device-list updates from bridged rooms, and verify that missing Device references no longer crash the WASM OlmMachine while to-device key shares continue processing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript, wasm
- Domain
- security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100