diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 8458f9c733d..a353619eacb 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -58,6 +58,14 @@ config SIM_CYGWIN_DECORATED run: It will crash early, probably in some function due to the failure to allocate memory. +config SIM_SANITIZE + bool "Address Sanitizer" + default n + depends on MM_CUSTOMIZE_MANAGER + ---help--- + AddressSanitizer (ASan) is a fast compiler-based tool for detecting memory + bugs in native code. + choice prompt "X64_64 ABI" default SIM_X8664_SYSTEMV if HOST_LINUX diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index 5607ed36ccf..2b6752f927d 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -76,7 +76,7 @@ CSRCS = up_initialize.c up_idle.c up_interruptcontext.c up_initialstate.c CSRCS += up_createstack.c up_usestack.c up_releasestack.c up_stackframe.c CSRCS += up_unblocktask.c up_blocktask.c up_releasepending.c CSRCS += up_reprioritizertr.c up_exit.c up_schedulesigaction.c -CSRCS += up_allocateheap.c up_uart.c +CSRCS += up_heap.c up_uart.c ifeq ($(CONFIG_ARCH_HAVE_VFORK),y) ifeq ($(CONFIG_SCHED_WAITPID),y) diff --git a/arch/sim/src/nuttx-names.in b/arch/sim/src/nuttx-names.in index dab2123aea3..9e30d90ace2 100644 --- a/arch/sim/src/nuttx-names.in +++ b/arch/sim/src/nuttx-names.in @@ -48,6 +48,8 @@ NXSYMBOLS(if_nametoindex) NXSYMBOLS(ioctl) NXSYMBOLS(lseek) NXSYMBOLS(malloc) +NXSYMBOLS(mallinfo) +NXSYMBOLS(memalign) NXSYMBOLS(memcpy) NXSYMBOLS(mkdir) NXSYMBOLS(mmap) @@ -73,6 +75,7 @@ NXSYMBOLS(pthread_sigmask) NXSYMBOLS(read) NXSYMBOLS(readdir) NXSYMBOLS(readv) +NXSYMBOLS(realloc) NXSYMBOLS(rename) NXSYMBOLS(rewinddir) NXSYMBOLS(rmdir) diff --git a/arch/sim/src/sim/up_allocateheap.c b/arch/sim/src/sim/up_allocateheap.c deleted file mode 100644 index ae440402263..00000000000 --- a/arch/sim/src/sim/up_allocateheap.c +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** - * arch/sim/src/sim/up_allocateheap.c - * - * Copyright (C) 2007-2009, 2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include - -#include "up_internal.h" - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_allocate_heap - * - * Description: - * This function will be called to dynamically set aside the heap region. - * - * If a protected kernel-space heap is provided, the kernel heap must be - * allocated (and protected) by an analogous up_allocate_kheap(). - * - ****************************************************************************/ - -void up_allocate_heap(void **heap_start, size_t *heap_size) -{ - /* Note: Some subsystems like modlib and binfmt need to allocate - * executable memory. - */ - - /* We make the entire heap executable here to keep - * the sim simpler. If it turns out to be a problem, the - * ARCH_HAVE_MODULE_TEXT mechanism can be an alternative. - */ - - uint8_t *sim_heap = host_alloc_heap(SIM_HEAP_SIZE); - - *heap_start = sim_heap; - *heap_size = SIM_HEAP_SIZE; -} diff --git a/arch/sim/src/sim/up_heap.c b/arch/sim/src/sim/up_heap.c new file mode 100644 index 00000000000..2dd0e847193 --- /dev/null +++ b/arch/sim/src/sim/up_heap.c @@ -0,0 +1,470 @@ +/**************************************************************************** + * arch/sim/src/sim/up_heap.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "up_internal.h" + +#ifdef CONFIG_MM_CUSTOMIZE_MANAGER + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This describes one heap (possibly with multiple regions) */ + +struct mm_delaynode_s +{ + FAR struct mm_delaynode_s *flink; +}; + +struct mm_heap_impl_s +{ + struct mm_delaynode_s *mm_delaylist; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__) +static void mm_add_delaylist(FAR struct mm_heap_s *heap, FAR void *mem) +{ + FAR struct mm_delaynode_s *tmp = mem; + irqstate_t flags; + + /* Delay the deallocation until a more appropriate time. */ + + flags = enter_critical_section(); + + tmp->flink = heap->mm_impl->mm_delaylist; + heap->mm_impl->mm_delaylist = tmp; + + leave_critical_section(flags); +} + +#endif + +static void mm_free_delaylist(FAR struct mm_heap_s *heap) +{ +#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__) + FAR struct mm_delaynode_s *tmp; + irqstate_t flags; + + /* Move the delay list to local */ + + flags = enter_critical_section(); + + tmp = heap->mm_impl->mm_delaylist; + heap->mm_impl->mm_delaylist = NULL; + + leave_critical_section(flags); + + /* Test if the delayed is empty */ + + while (tmp) + { + FAR void *address; + + /* Get the first delayed deallocation */ + + address = tmp; + tmp = tmp->flink; + + /* The address should always be non-NULL since that was checked in the + * 'while' condition above. + */ + + mm_free(heap, address); + } +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mm_initialize + * + * Description: + * Initialize the selected heap data structures, providing the initial + * heap region. + * + * Input Parameters: + * heap - The selected heap + * heapstart - Start of the initial heap region + * heapsize - Size of the initial heap region + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +void mm_initialize(FAR struct mm_heap_s *heap, FAR void *heap_start, + size_t heap_size) +{ + FAR struct mm_heap_impl_s *impl; + impl = host_malloc(sizeof(struct mm_heap_impl_s)); + impl->mm_delaylist = NULL; + heap->mm_impl = impl; +} + +/**************************************************************************** + * Name: mm_addregion + * + * Description: + * This function adds a region of contiguous memory to the selected heap. + * + * Input Parameters: + * heap - The selected heap + * heapstart - Start of the heap region + * heapsize - Size of the heap region + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart, + size_t heapsize) +{ +} + +/**************************************************************************** + * Name: mm_malloc + * + * Description: + * Find the smallest chunk that satisfies the request. Take the memory from + * that chunk, save the remaining, smaller chunk (if any). + * + * 8-byte alignment of the allocated data is assured. + * + ****************************************************************************/ + +FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) +{ + /* Firstly, free mm_delaylist */ + + mm_free_delaylist(heap); + return host_malloc(size); +} + +/**************************************************************************** + * Name: mm_free + * + * Description: + * Returns a chunk of memory to the list of free nodes, merging with + * adjacent free chunks if possible. + * + ****************************************************************************/ + +FAR void mm_free(FAR struct mm_heap_s *heap, FAR void *mem) +{ +#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__) + int ret = (int)getpid(); + + /* Check current environment */ + + if (up_interrupt_context()) + { + /* We are in ISR, add to mm_delaylist */ + + mm_add_delaylist(heap, mem); + } + else if (ret == -ESRCH || sched_idletask()) + { + /* We are in IDLE task & can't get sem, or meet -ESRCH return, + * which means we are in situations during context switching(See + * mm_trysemaphore() & getpid()). Then add to mm_delaylist. + */ + + mm_add_delaylist(heap, mem); + } + else +#endif + { + host_free(mem); + } + + return; +} + +/**************************************************************************** + * Name: mm_realloc + * + * Description: + * If the reallocation is for less space, then: + * + * (1) the current allocation is reduced in size + * (2) the remainder at the end of the allocation is returned to the + * free list. + * + * If the request is for more space and the current allocation can be + * extended, it will be extended by: + * + * (1) Taking the additional space from the following free chunk, or + * (2) Taking the additional space from the preceding free chunk. + * (3) Or both + * + * If the request is for more space but the current chunk cannot be + * extended, then malloc a new buffer, copy the data into the new buffer, + * and free the old buffer. + * + ****************************************************************************/ + +FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, + size_t size) +{ + mm_free_delaylist(heap); + return host_realloc(oldmem, size); +} + +/**************************************************************************** + * Name: mm_calloc + * + * Descriptor: + * mm_calloc() calculates the size of the allocation and calls mm_zalloc() + * + ****************************************************************************/ + +FAR void *mm_calloc(FAR struct mm_heap_s *heap, size_t n, size_t elem_size) +{ + mm_free_delaylist(heap); + return host_calloc(n, elem_size); +} + +/**************************************************************************** + * Name: mm_zalloc + * + * Description: + * mm_zalloc calls mm_malloc, then zeroes out the allocated chunk. + * + ****************************************************************************/ + +FAR void *mm_zalloc(FAR struct mm_heap_s *heap, size_t size) +{ + FAR void *ptr; + + ptr = mm_malloc(heap, size); + if (ptr != NULL) + { + memset(ptr, 0, size); + } + + return ptr; +} + +/**************************************************************************** + * Name: mm_memalign + * + * Description: + * memalign requests more than enough space from malloc, finds a region + * within that chunk that meets the alignment request and then frees any + * leading or trailing space. + * + * The alignment argument must be a power of two (not checked). 8-byte + * alignment is guaranteed by normal malloc calls. + * + ****************************************************************************/ + +FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment, + size_t size) +{ + mm_free_delaylist(heap); + return host_memalign(alignment, size); +} + +/**************************************************************************** + * Name: mm_heapmember + * + * Description: + * Check if an address lies in the heap. + * + * Parameters: + * heap - The heap to check + * mem - The address to check + * + * Return Value: + * true if the address is a member of the heap. false if not + * not. If the address is not a member of the heap, then it + * must be a member of the user-space heap (unchecked) + * + ****************************************************************************/ + +bool mm_heapmember(FAR struct mm_heap_s *heap, FAR void *mem) +{ + return true; +} + +/**************************************************************************** + * Name: mm_brkaddr + * + * Description: + * Return the break address of a heap region. Zero is returned if the + * memory region is not initialized. + * + ****************************************************************************/ + +FAR void *mm_brkaddr(FAR struct mm_heap_s *heap, int region) +{ + return NULL; +} + +/**************************************************************************** + * Name: mm_sbrk + * + * Description: + * The sbrk() function is used to change the amount of space allocated + * for the calling process. The change is made by resetting the process's + * break value and allocating the appropriate amount of space. The amount + * of allocated space increases as the break value increases. + * + * The sbrk() function adds 'incr' bytes to the break value and changes + * the allocated space accordingly. If incr is negative, the amount of + * allocated space is decreased by incr bytes. The current value of the + * program break is returned by sbrk(0). + * + * Input Parameters: + * heap - A reference to the data structure that defines this heap. + * incr - Specifies the number of bytes to add or to remove from the + * space allocated for the process. + * maxbreak - The maximum permissible break address. + * + * Returned Value: + * Upon successful completion, sbrk() returns the prior break value. + * Otherwise, it returns (void *)-1 and sets errno to indicate the + * error: + * + * ENOMEM - The requested change would allocate more space than + * allowed under system limits. + * EAGAIN - The total amount of system memory available for allocation + * to this process is temporarily insufficient. This may occur even + * though the space requested was less than the maximum data segment + * size. + * + ****************************************************************************/ + +FAR void *mm_sbrk(FAR struct mm_heap_s *heap, intptr_t incr, + uintptr_t maxbreak) +{ + return NULL; +} + +/**************************************************************************** + * Name: mm_extend + * + * Description: + * Extend a heap region by add a block of (virtually) contiguous memory + * to the end of the heap. + * + ****************************************************************************/ + +void mm_extend(FAR struct mm_heap_s *heap, FAR void *mem, size_t size, + int region) +{ +} + +/**************************************************************************** + * Name: mm_mallinfo + * + * Description: + * mallinfo returns a copy of updated current heap information. + * + ****************************************************************************/ + +int mm_mallinfo(FAR struct mm_heap_s *heap, FAR struct mallinfo *info) +{ + struct host_mallinfo hostinfo; + + host_mallinfo(&hostinfo); + memcpy(info, &hostinfo, sizeof(struct mallinfo)); + return 0; +} + +#ifdef CONFIG_DEBUG_MM + +/**************************************************************************** + * Name: mm_checkcorruption + * + * Description: + * mm_checkcorruption is used to check whether memory heap is normal. + * + ****************************************************************************/ + +void mm_checkcorruption(FAR struct mm_heap_s *heap) +{ +} + +#endif /* CONFIG_DEBUG_MM */ + + +/**************************************************************************** + * Name: up_allocate_heap + * + * Description: + * This function will be called to dynamically set aside the heap region. + * + * If a protected kernel-space heap is provided, the kernel heap must be + * allocated (and protected) by an analogous up_allocate_kheap(). + * + ****************************************************************************/ + +void up_allocate_heap(void **heap_start, size_t *heap_size) +{ + *heap_start = NULL; + *heap_size = 0; +} + +#else /* CONFIG_MM_CUSTOMIZE_MANAGER */ + +void up_allocate_heap(void **heap_start, size_t *heap_size) +{ + /* Note: Some subsystems like modlib and binfmt need to allocate + * executable memory. + */ + + /* We make the entire heap executable here to keep + * the sim simpler. If it turns out to be a problem, the + * ARCH_HAVE_MODULE_TEXT mechanism can be an alternative. + */ + + uint8_t *sim_heap = host_alloc_heap(SIM_HEAP_SIZE); + + *heap_start = sim_heap; + *heap_size = SIM_HEAP_SIZE; +} + +#endif /* CONFIG_MM_CUSTOMIZE_MANAGER */ diff --git a/arch/sim/src/sim/up_hostmemory.c b/arch/sim/src/sim/up_hostmemory.c index 0950fd5a917..7d306c88e8a 100644 --- a/arch/sim/src/sim/up_hostmemory.c +++ b/arch/sim/src/sim/up_hostmemory.c @@ -25,10 +25,14 @@ #include #include #include +#include +#include #include #include +#include "up_internal.h" + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -113,3 +117,40 @@ void host_free_shmem(void *mem) { munmap(mem, 0); } + +void *host_malloc(size_t size) +{ + return malloc(size); +} + +void host_free(void *mem) +{ + free(mem); +} + +void *host_realloc(void *oldmem, size_t size) +{ + return realloc(oldmem, size); +} + +void *host_calloc(size_t n, size_t elem_size) +{ + return calloc(n , elem_size); +} + +void *host_memalign(size_t alignment, size_t size) +{ + return memalign(alignment, size); +} + +void host_mallinfo(struct host_mallinfo *info) +{ + struct mallinfo tmp; + + tmp = mallinfo(); + info->arena = tmp.arena; + info->ordblks = tmp.ordblks; + info->mxordblk = tmp.usmblks; + info->uordblks = tmp.uordblks; + info->fordblks = tmp.fordblks; +} diff --git a/arch/sim/src/sim/up_internal.h b/arch/sim/src/sim/up_internal.h index 034a4cd7152..1af2c7daec5 100644 --- a/arch/sim/src/sim/up_internal.h +++ b/arch/sim/src/sim/up_internal.h @@ -169,6 +169,20 @@ struct qspi_dev_s; struct ioexpander_dev_s; struct i2c_master_s; +/* This describes the information about memory allocations */ + +struct host_mallinfo +{ + int arena; /* This is the total size of memory allocated + * for use by malloc in bytes. */ + int ordblks; /* This is the number of free (not in use) chunks */ + int mxordblk; /* Size of the largest free (not in use) chunk */ + int uordblks; /* This is the total size of memory occupied by + * chunks handed out by malloc. */ + int fordblks; /* This is the total size of memory occupied + * by free (not in use) chunks. */ +}; + /**************************************************************************** * Public Data ****************************************************************************/ @@ -230,6 +244,12 @@ void up_longjmp(void *jb, int val); void *host_alloc_heap(size_t sz); void *host_alloc_shmem(const char *name, size_t size, int master); void host_free_shmem(void *mem); +void *host_malloc(size_t size); +void host_free(void *mem); +void *host_realloc(void *oldmem, size_t size); +void *host_calloc(size_t n, size_t elem_size); +void *host_memalign(size_t alignment, size_t size); +void host_mallinfo(struct host_mallinfo *info); /* up_hosttime.c ************************************************************/ diff --git a/boards/sim/sim/sim/scripts/Make.defs b/boards/sim/sim/sim/scripts/Make.defs index f7dc83665f6..1e5a30f75ab 100644 --- a/boards/sim/sim/sim/scripts/Make.defs +++ b/boards/sim/sim/sim/scripts/Make.defs @@ -53,6 +53,10 @@ ifeq ($(CONFIG_STACK_CANARIES),y) ARCHOPTIMIZATION += -fstack-protector-all endif +ifeq ($(CONFIG_SIM_SANITIZE),y) + ARCHOPTIMIZATION += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer +endif + ARCHCPUFLAGS = -fno-builtin ARCHCPUFLAGSXX = -fno-builtin -nostdinc++ -fcheck-new ifeq ($(CONFIG_CXX_EXCEPTION),) @@ -163,5 +167,9 @@ ifeq ($(CONFIG_SIM_M32),y) HOSTLDFLAGS += -m32 endif +ifeq ($(CONFIG_SIM_SANITIZE),y) + CCLINKFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer +endif + HOSTCFLAGS = $(ARCHWARNINGS) $(ARCHOPTIMIZATION) \ $(ARCHCPUFLAGS) $(HOSTINCLUDES) $(EXTRAFLAGS) -pipe