Skip to content

Null pointer crash in receiveSyncChanges via DehydratedDevices #5187

@DrDrewCain

Description

@DrDrewCain

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:

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-Element-RIssues affecting the port of Element's crypto layer to RustT-Defect

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions