<commit_before>use crate::alloc::{host_page_size, instance_heap_offset, Alloc, Limits, Slot};
use crate::embed_ctx::CtxMap;
use crate::error::Error;
use crate::instance::{new_instance_handle, Instance, InstanceHandle};
use crate::module::Module;
use crate::region::{Region, RegionCreate, RegionInternal};
use libc::c_void;
#[cfg(not(target_os = "linux"))]
use libc::memset;
use nix::sys::mman::{madvise, mmap, munmap, MapFlags, MmapAdvise, ProtFlags};
use std::cmp::Ordering;
use std::ptr;
use std::sync::{Arc, RwLock, Weak};

/// A [`Region`](../trait.Region.html) backed by `mmap`.
///
/// `MmapRegion` lays out memory for instances in a contiguous block,
/// with an Instance's space reserved, followed by heap, stack, globals, and sigstack.
///
/// This results in an actual layout of an instance on an `MmapRegion`-produced `Slot` being:
/// ```text
/// 0x0000: +-----------------------+ <-- Instance
/// 0x0000: |  .magic               |
/// 0x0008: |  ...                  |
/// 0x000X: |  ...                  |
/// 0x0XXX: |  .alloc -> Alloc {    |
/// 0x0XXX: |    .start    = 0x0000 |
/// 0x0XXX: |    .heap     = 0x1000 |
/// 0x0XXX: |    .stack    = 0xN000 |
/// 0x0XXX: |    .globals  = 0xM000 |
/// 0x0XXX: |    .sigstack = 0xS000 |
/// 0x0XXX: |  }                    |
/// 0x0XXX: |  ...                  |
/// 0x0XXX: ~      ~padding~        ~
/// 0x0XXX: |  ...                  |
/// 0x0XXX: |  .globals    = 0xM000 | <-- InstanceRuntimeData
/// 0x0XXX: |  .inst_count = 0x0000 |
/// 0x1000: +-----------------------+ <-- Heap, and `lucet_vmctx`. One page into the allocation.
/// 0x1XXX: |                       |
/// 0xXXXX: ~  .......heap.......   ~ // heap size is governed by limits.heap_address_space_size
/// 0xXXXX: |                       |
/// 0xN000: +-----------------------| <-- Stack (at heap_start + limits.heap_address_space_size)
/// 0xNXXX: --- stack guard page ----
/// 0xNXXX: |                       |
/// 0xXXXX: ~  .......stack......   ~ // stack size is governed by limits.stack_size
/// 0xXXXX: |                       |
/// 0xM000: +-----------------------| <-- Globals (at stack_start + limits.stack_size + PAGE_SIZE)
/// 0xMXXX: |                       |
/// 0xXXXX: ~  ......globals.....   ~
/// 0xXXXX: |                       |
/// 0xXXXX  --- global guard page ---
/// 0xS000: +-----------------------| <-- Sigstack (at globals_start + globals_size + PAGE_SIZE)
/// 0xSXXX: |  ......sigstack....   | // sigstack is governed by limits.signal_stack_size
/// 0xSXXX: +-----------------------|
/// ```
pub struct MmapRegion {
    capacity: usize,
    freelist: RwLock<Vec<Slot>>,
    limits: Limits,
    min_heap_alignment: usize,
}

impl Region for MmapRegion {
    fn free_slots(&self) -> usize {
        self.freelist.read().unwrap().len()
    }

    fn used_slots(&self) -> usize {
        self.capacity() - self.free_slots()
    }

    fn capacity(&self) -> usize {
        self.capacity
    }
}

impl RegionInternal for MmapRegion {
    fn new_instance_with(
        &self,
        module: Arc<dyn Module>,
        embed_ctx: CtxMap,
        heap_memory_size_limit: usize,
    ) -> Result<InstanceHandle, Error> {
        let custom_limits;
        let mut limits = self.get_limits();

        // Affirm that the module, if instantiated, would not violate
        // any runtime memory limits.
        match heap_memory_size_limit.cmp(&limits.heap_memory_size) {
            Ordering::Less => {
                // The supplied heap_memory_size is smaller than
                // default. Augment the limits with this custom value
                // so that it may be validated.
                custom_limits = Limits {
                    heap_memory_size: heap_memory_size_limit,
                    ..*limits
                };
                limits = &custom_limits;
            }
            Ordering::Equal => (),
            Ordering::Greater => {
                return Err(Error::InvalidArgument(
                    "heap memory size requested for instance is larger than slot allows",
                ))
            }
        }
        module.validate_runtime_spec(&limits)?;

        let slot = self
            .freelist
            .write()
            .unwrap()
            .pop()
            .ok_or(Error::RegionFull(self.capacity))?;

        if slot.heap as usize % host_page_size() != 0 {
            lucet_bail!("heap is not page-aligned; this is a bug");
        }

        for (ptr, len) in [
            // make the stack read/writable
            (slot.stack, limits.stack_size),
            // make the globals read/writable
            (slot.globals, limits.globals_size),
            // make the sigstack read/writable
            (slot.sigstack, limits.signal_stack_size),
        ]
        .iter()
        {
            unsafe {<commit_msg>When the heap is not page aligned, fail instead of `lucet_bail` (#486)<commit_after>use crate::alloc::{host_page_size, instance_heap_offset, Alloc, Limits, Slot};
use crate::embed_ctx::CtxMap;
use crate::error::Error;
use crate::instance::{new_instance_handle, Instance, InstanceHandle};
use crate::module::Module;
use crate::region::{Region, RegionCreate, RegionInternal};
use libc::c_void;
#[cfg(not(target_os = "linux"))]
use libc::memset;
use nix::sys::mman::{madvise, mmap, munmap, MapFlags, MmapAdvise, ProtFlags};
use std::cmp::Ordering;
use std::ptr;
use std::sync::{Arc, RwLock, Weak};

/// A [`Region`](../trait.Region.html) backed by `mmap`.
///
/// `MmapRegion` lays out memory for instances in a contiguous block,
/// with an Instance's space reserved, followed by heap, stack, globals, and sigstack.
///
/// This results in an actual layout of an instance on an `MmapRegion`-produced `Slot` being:
/// ```text
/// 0x0000: +-----------------------+ <-- Instance
/// 0x0000: |  .magic               |
/// 0x0008: |  ...                  |
/// 0x000X: |  ...                  |
/// 0x0XXX: |  .alloc -> Alloc {    |
/// 0x0XXX: |    .start    = 0x0000 |
/// 0x0XXX: |    .heap     = 0x1000 |
/// 0x0XXX: |    .stack    = 0xN000 |
/// 0x0XXX: |    .globals  = 0xM000 |
/// 0x0XXX: |    .sigstack = 0xS000 |
/// 0x0XXX: |  }                    |
/// 0x0XXX: |  ...                  |
/// 0x0XXX: ~      ~padding~        ~
/// 0x0XXX: |  ...                  |
/// 0x0XXX: |  .globals    = 0xM000 | <-- InstanceRuntimeData
/// 0x0XXX: |  .inst_count = 0x0000 |
/// 0x1000: +-----------------------+ <-- Heap, and `lucet_vmctx`. One page into the allocation.
/// 0x1XXX: |                       |
/// 0xXXXX: ~  .......heap.......   ~ // heap size is governed by limits.heap_address_space_size
/// 0xXXXX: |                       |
/// 0xN000: +-----------------------| <-- Stack (at heap_start + limits.heap_address_space_size)
/// 0xNXXX: --- stack guard page ----
/// 0xNXXX: |                       |
/// 0xXXXX: ~  .......stack......   ~ // stack size is governed by limits.stack_size
/// 0xXXXX: |                       |
/// 0xM000: +-----------------------| <-- Globals (at stack_start + limits.stack_size + PAGE_SIZE)
/// 0xMXXX: |                       |
/// 0xXXXX: ~  ......globals.....   ~
/// 0xXXXX: |                       |
/// 0xXXXX  --- global guard page ---
/// 0xS000: +-----------------------| <-- Sigstack (at globals_start + globals_size + PAGE_SIZE)
/// 0xSXXX: |  ......sigstack....   | // sigstack is governed by limits.signal_stack_size
/// 0xSXXX: +-----------------------|
/// ```
pub struct MmapRegion {
    capacity: usize,
    freelist: RwLock<Vec<Slot>>,
    limits: Limits,
    min_heap_alignment: usize,
}

impl Region for MmapRegion {
    fn free_slots(&self) -> usize {
        self.freelist.read().unwrap().len()
    }

    fn used_slots(&self) -> usize {
        self.capacity() - self.free_slots()
    }

    fn capacity(&self) -> usize {
        self.capacity
    }
}

impl RegionInternal for MmapRegion {
    fn new_instance_with(
        &self,
        module: Arc<dyn Module>,
        embed_ctx: CtxMap,
        heap_memory_size_limit: usize,
    ) -> Result<InstanceHandle, Error> {
        let custom_limits;
        let mut limits = self.get_limits();

        // Affirm that the module, if instantiated, would not violate
        // any runtime memory limits.
        match heap_memory_size_limit.cmp(&limits.heap_memory_size) {
            Ordering::Less => {
                // The supplied heap_memory_size is smaller than
                // default. Augment the limits with this custom value
                // so that it may be validated.
                custom_limits = Limits {
                    heap_memory_size: heap_memory_size_limit,
                    ..*limits
                };
                limits = &custom_limits;
            }
            Ordering::Equal => (),
            Ordering::Greater => {
                return Err(Error::InvalidArgument(
                    "heap memory size requested for instance is larger than slot allows",
                ))
            }
        }
        module.validate_runtime_spec(&limits)?;

        let slot = self
            .freelist
            .write()
            .unwrap()
            .pop()
            .ok_or(Error::RegionFull(self.capacity))?;

        assert_eq!(
            slot.heap as usize % host_page_size(),
            0,
            "heap must be page-aligned"
        );

        for (ptr, len) in [
            // make the stack read/writable
            (slot.stack, limits.stack_size),
            // make the globals read/writable
            (slot.globals, limits.globals_size),
            // make the sigstack read/writable
            (slot.sigstack, limits.signal_stack_size),
        ]
        .iter()
        {
            unsafe {
{'fraction_non_alphanumeric': 0.17463424685761383, 'fraction_numerical': 0.02215124665155574, 'mean_word_length': 1.5598628691983123, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4226645', 'n_tokens_mistral': 3174, 'n_tokens_neox': 2926, 'n_words': 687}