Account Reallocation Remediation
How to fix unsafe account reallocation patterns.
Account Reallocation Remediation
Overview
Detector Reference: Account Reallocation
This guide explains how to safely resize Solana accounts, covering zero-fill, rent exemption, discriminator validation, and data preservation.
Recommended Fix
Follow this four-step pattern for every reallocation:
// Step 1: Read existing data
let old_data = MyAccount::try_from_slice(&account.data.borrow())?;
// Step 2: Realloc with zero-fill enabled
account.realloc(new_size, true)?;
// Step 3: Ensure rent exemption
let rent = Rent::get()?;
let required_lamports = rent.minimum_balance(new_size);
if account.lamports() < required_lamports {
let diff = required_lamports - account.lamports();
**payer.try_borrow_mut_lamports()? -= diff;
**account.try_borrow_mut_lamports()? += diff;
}
// Step 4: Re-validate and write migrated data
let mut data = account.data.borrow_mut();
require!(data[0..8] == MyAccount::DISCRIMINATOR, InvalidDiscriminator);
old_data.migrate(new_size).serialize(&mut &mut data[..])?;
Alternative Mitigations
- Use Anchor’s realloc constraint:
#[account(mut, realloc = size, realloc::payer = payer, realloc::zero = true)]handles zero-fill and rent automatically. - Manual memset: if you cannot use
realloc(_, true), zero new space withsol_memset(&mut data[old_size..], 0, new_size - old_size). - Reject shrinking: if your account layout does not support migration, reject realloc requests that reduce size.
Common Mistakes
- Setting
realloc::zero = false: leaves stale data in newly allocated space, risking information leakage. - Forgetting rent adjustment: the account may be garbage-collected if lamports are insufficient for the new size.
- Skipping discriminator revalidation: after realloc, the data layout may be invalid; always re-check the discriminator.
- Not reading data before realloc: shrinking destroys data beyond the new boundary. Read first, migrate, then write.