nuttx/mm/mm_heap/mm_free.c
chao.an 27c888854d mm_heap/kasan: poison free node after return back the heap list
The free node is still in use after kasan_poison(), the node member
access will cause the assert report by kasan.

|  (gdb) bt
|  #0  kasan_report (addr=1743265406637584896, size=140737337053680, is_write=46) at kasan/kasan.c:97
|  #1  0x0000555555607bdd in __asan_loadN_noabort (addr=140737272831420, size=4) at kasan/kasan.c:289
|  #2  0x0000555555607cd7 in __asan_load4_noabort (addr=140737272831420) at kasan/kasan.c:323
|  #3  0x00005555556061ef in gmtime_r (timep=0x7ffff3275dbc, result=0x7ffff3275e10) at time/lib_gmtimer.c:301
|  #4  0x000055555560e507 in sim_rtc_rdtime (lower=0x55555576b780 <g_sim_rtc>, rtctime=0x7ffff3275e10) at sim/up_rtc.c:77
|  #5  0x00005555555fcbdb in up_rtc_gettime (tp=0x7ffff3275ef0) at timers/arch_rtc.c:128
|  #6  0x00005555555f08b4 in clock_systime_timespec (ts=0x7ffff3275ef0) at clock/clock_systime_timespec.c:72
|  #7  0x00005555555ecc77 in note_common (tcb=0x7ffff31d2180, note=0x7ffff3275f80, length=21 '\025', type=18 '\022') at sched/sched_note.c:144
|  #8  0x00005555555ed706 in sched_note_syscall_enter (nr=1, argc=0) at sched/sched_note.c:765
|  #9  0x000055555560eb37 in __wrap_getpid () at wraps/WRAP_getpid.c:26
|  #10 0x0000555555608d1c in mm_takesemaphore (heap=0x7ffff30ae000) at mm_heap/mm_sem.c:127
|  #11 0x0000555555609477 in mm_free (heap=0x7ffff30ae000, mem=0x7ffff3265b80) at mm_heap/mm_free.c:89
|  #12 0x00005555556070c5 in free (mem=0x7ffff3265b80) at umm_heap/umm_free.c:49
|  #13 0x000055555560c3b0 in up_release_stack (dtcb=0x7ffff31e4b00, ttype=0 '\000') at sim/up_releasestack.c:67
|  #14 0x00005555555f2515 in nxsched_release_tcb (tcb=0x7ffff31e4b00, ttype=0 '\000') at sched/sched_releasetcb.c:134
|  #15 0x00005555556bdf0c in nxtask_terminate (pid=4, nonblocking=true) at task/task_terminate.c:184
|  #16 0x00005555556bdb0f in nxtask_exit () at task/task_exit.c:168
|  #17 0x000055555566e05f in up_exit (status=0) at sim/up_exit.c:64
|  #18 0x000055555564f454 in _exit (status=0) at task/exit.c:78
|  #19 0x000055555560ea89 in __wrap__exit (parm1=0) at wraps/WRAP__exit.c:27
|  #20 0x00005555555eb288 in exit (status=0) at stdlib/lib_exit.c:54
|  #21 0x00005555555fe2cc in nxtask_startup (entrypt=0x555555670c34 <critmon_start_main>, argc=1, argv=0x7ffff3265bb0) at sched/task_startup.c:70
|  #22 0x00005555555f02a0 in nxtask_start () at task/task_start.c:134
|  #23 0x0000000000000000 in ?? ()

Signed-off-by: chao.an <anchao@xiaomi.com>
2022-08-02 01:45:08 +08:00

179 lines
5.2 KiB
C

/****************************************************************************
* mm/mm_heap/mm_free.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 <nuttx/config.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/mm/mm.h>
#include "mm_heap/mm.h"
#include "kasan/kasan.h"
/****************************************************************************
* Private Functions
****************************************************************************/
static void mm_add_delaylist(FAR struct mm_heap_s *heap, FAR void *mem)
{
#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__)
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_delaylist[up_cpu_index()];
heap->mm_delaylist[up_cpu_index()] = tmp;
leave_critical_section(flags);
#endif
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mm_free
*
* Description:
* Returns a chunk of memory to the list of free nodes, merging with
* adjacent free chunks if possible.
*
****************************************************************************/
void mm_free(FAR struct mm_heap_s *heap, FAR void *mem)
{
FAR struct mm_freenode_s *node;
FAR struct mm_freenode_s *prev;
FAR struct mm_freenode_s *next;
int ret;
UNUSED(ret);
minfo("Freeing %p\n", mem);
/* Protect against attempts to free a NULL reference */
if (!mem)
{
return;
}
if (mm_takesemaphore(heap) == false)
{
/* Meet -ESRCH return, which means we are in situations
* during context switching(See mm_takesemaphore() & getpid()).
* Then add to the delay list.
*/
mm_add_delaylist(heap, mem);
return;
}
kasan_poison(mem, mm_malloc_size(mem));
DEBUGASSERT(mm_heapmember(heap, mem));
/* Map the memory chunk into a free node */
node = (FAR struct mm_freenode_s *)((FAR char *)mem - SIZEOF_MM_ALLOCNODE);
/* Sanity check against double-frees */
DEBUGASSERT(node->preceding & MM_ALLOC_BIT);
node->preceding &= ~MM_ALLOC_BIT;
/* Check if the following node is free and, if so, merge it */
next = (FAR struct mm_freenode_s *)((FAR char *)node + node->size);
DEBUGASSERT((next->preceding & ~MM_ALLOC_BIT) == node->size);
if ((next->preceding & MM_ALLOC_BIT) == 0)
{
FAR struct mm_allocnode_s *andbeyond;
/* Get the node following the next node (which will
* become the new next node). We know that we can never
* index past the tail chunk because it is always allocated.
*/
andbeyond = (FAR struct mm_allocnode_s *)
((FAR char *)next + next->size);
/* Remove the next node. There must be a predecessor,
* but there may not be a successor node.
*/
DEBUGASSERT(next->blink);
next->blink->flink = next->flink;
if (next->flink)
{
next->flink->blink = next->blink;
}
/* Then merge the two chunks */
node->size += next->size;
andbeyond->preceding = node->size |
(andbeyond->preceding & MM_ALLOC_BIT);
next = (FAR struct mm_freenode_s *)andbeyond;
}
/* Check if the preceding node is also free and, if so, merge
* it with this node
*/
prev = (FAR struct mm_freenode_s *)((FAR char *)node - node->preceding);
DEBUGASSERT((node->preceding & ~MM_ALLOC_BIT) == prev->size);
if ((prev->preceding & MM_ALLOC_BIT) == 0)
{
/* Remove the node. There must be a predecessor, but there may
* not be a successor node.
*/
DEBUGASSERT(prev->blink);
prev->blink->flink = prev->flink;
if (prev->flink)
{
prev->flink->blink = prev->blink;
}
/* Then merge the two chunks */
prev->size += node->size;
next->preceding = prev->size | (next->preceding & MM_ALLOC_BIT);
node = prev;
}
/* Add the merged node to the nodelist */
mm_addfreechunk(heap, node);
mm_givesemaphore(heap);
}