Skip to content

Bug: ArrayBuffer allocator doesn't rollback count on failed allocation #645

@max-lt

Description

@max-lt
  • I confirm this is a bug with Supabase, not with my own application.
  • I confirm I have searched the Docs, GitHub Discussions, and Discord.

In ext/runtime/external_memory.rs, when an allocation exceeds the limit, the count is incremented but never rolled back on failure.

allocate and allocate_uninitialized

  unsafe extern "C" fn allocate(allocator: &CustomAllocator, n: usize) -> *mut c_void {
      allocator.count.fetch_add(n, Ordering::SeqCst);  // count += n

      let count_loaded = allocator.count.load(Ordering::SeqCst);

      if count_loaded > allocator.max {
          return std::ptr::null::<*mut [u8]>() as *mut c_void;  // returns without rollback
      }
      // ...
  }

reallocate

  unsafe extern "C" fn reallocate(
    allocator: &CustomAllocator,
    prev: *mut c_void,
    oldlen: usize,
    newlen: usize,
  ) -> *mut c_void {
    allocator
      .count
      .fetch_add(newlen.wrapping_sub(oldlen), Ordering::SeqCst);  // count += (newlen - oldlen)

    let count_loaded = allocator.count.load(Ordering::SeqCst);

    if count_loaded > allocator.max {
      return std::ptr::null::<*mut [u8]>() as *mut c_void;  // returns without rollback
    }
    // ...
  }

Impact

Attempt 1: allocate(100MB), limit=50MB → count=100MB → FAIL → count stays 100MB
Attempt 2: allocate(1KB) → count=100MB+1KB → FAIL (even though 1KB < 50MB)

All future allocations fail permanently, even small legitimate ones.

Fix

  // allocate / allocate_uninitialized
  if count_loaded > allocator.max {
      allocator.count.fetch_sub(n, Ordering::SeqCst);  // rollback
      return std::ptr::null::<*mut [u8]>() as *mut c_void;
  }

  // reallocate
  if count_loaded > allocator.max {
      allocator.count.fetch_sub(newlen.wrapping_sub(oldlen), Ordering::SeqCst);  // rollback
      return std::ptr::null::<*mut [u8]>() as *mut c_void;
  }

Happy to open a PR if you'd like.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions