| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 | /* alloc.c * * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> * * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. *//* * Parts of the memalign code were stolen from malloc-930716. */#include <features.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdint.h>#include <errno.h>#include <sys/mman.h>#include <malloc.h>extern int weak_function __libc_free_aligned(void *ptr) attribute_hidden;#ifdef L_mallocvoid *malloc(size_t size){	void *result;	if (unlikely(size == 0)) {		size++;	}	/* prevent Undefined Behaviour for pointer arithmetic (substract) of too big pointers	 * see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63303	 * No need to check for size + sizeof(size_t) integer overflow since we already check for PTRDIFF_MAX	 */	if (unlikely(size > PTRDIFF_MAX)) {		__set_errno(ENOMEM);		return 0;	}#ifdef __ARCH_USE_MMU__# define MMAP_FLAGS MAP_PRIVATE | MAP_ANONYMOUS#else# define MMAP_FLAGS MAP_SHARED | MAP_ANONYMOUS | MAP_UNINITIALIZED#endif	result = mmap((void *) 0, size + sizeof(size_t), PROT_READ | PROT_WRITE,	              MMAP_FLAGS, 0, 0);	if (result == MAP_FAILED) {		__set_errno(ENOMEM);		return 0;	}	* (size_t *) result = size;	return(result + sizeof(size_t));}#endif#ifdef L_callocvoid * calloc(size_t nmemb, size_t lsize){	void *result;	size_t size=lsize * nmemb;	/* guard vs integer overflow, but allow nmemb	 * to fall through and call malloc(0) */	if (nmemb && lsize != (size / nmemb)) {		__set_errno(ENOMEM);		return NULL;	}	result = malloc(size);#ifndef __ARCH_USE_MMU__	/* mmap'd with MAP_UNINITIALIZED, we have to blank memory ourselves */	if (result != NULL) {		memset(result, 0, size);	}#endif	return result;}#endif#ifdef L_reallocvoid *realloc(void *ptr, size_t size){	void *newptr = NULL;	if (!ptr)		return malloc(size);	if (!size) {		free(ptr);		return malloc(0);	}	newptr = malloc(size);	if (newptr) {		size_t old_size = *((size_t *) (ptr - sizeof(size_t)));		memcpy(newptr, ptr, (old_size < size ? old_size : size));		free(ptr);	}	return newptr;}#endif#ifdef L_freevoid free(void *ptr){	if (unlikely(ptr == NULL))		return;	if (unlikely(__libc_free_aligned != NULL)) {		if (__libc_free_aligned(ptr))			return;	}	ptr -= sizeof(size_t);	munmap(ptr, * (size_t *) ptr + sizeof(size_t));}#endif#ifdef L_memalign#include <bits/uClibc_mutex.h>__UCLIBC_MUTEX_INIT(__malloc_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);#define __MALLOC_LOCK		__UCLIBC_MUTEX_LOCK(__malloc_lock)#define __MALLOC_UNLOCK		__UCLIBC_MUTEX_UNLOCK(__malloc_lock)/* List of blocks allocated with memalign or valloc */struct alignlist{	struct alignlist *next;	__ptr_t aligned;	/* The address that memaligned returned.  */	__ptr_t exact;	/* The address that malloc returned.  */};static struct alignlist *_aligned_blocks;/* Return memory to the heap. */int __libc_free_aligned(void *ptr){	struct alignlist *l;	if (ptr == NULL)		return 0;	__MALLOC_LOCK;	for (l = _aligned_blocks; l != NULL; l = l->next) {		if (l->aligned == ptr) {			/* Mark the block as free */			l->aligned = NULL;			ptr = l->exact;			ptr -= sizeof(size_t);			munmap(ptr, * (size_t *) ptr + sizeof(size_t));			return 1;		}	}	__MALLOC_UNLOCK;	return 0;}void * memalign (size_t alignment, size_t size){	void * result;	unsigned long int adj;	if (unlikely(size > PTRDIFF_MAX)) {		__set_errno(ENOMEM);		return NULL;	}	if (unlikely((size + alignment - 1 < size) && (alignment != 0))) {		__set_errno(ENOMEM);		return NULL;	}	result = malloc (size + alignment - 1);	if (result == NULL)		return NULL;	adj = (unsigned long int) ((unsigned long int) ((char *) result - (char *) NULL)) % alignment;	if (adj != 0) {		struct alignlist *l;		__MALLOC_LOCK;		for (l = _aligned_blocks; l != NULL; l = l->next)			if (l->aligned == NULL)				/* This slot is free.  Use it.  */				break;		if (l == NULL) {			l = (struct alignlist *) malloc (sizeof (struct alignlist));			if (l == NULL) {				free(result);				result = NULL;				goto DONE;			}			l->next = _aligned_blocks;			_aligned_blocks = l;		}		l->exact = result;		result = l->aligned = (char *) result + alignment - adj;DONE:		__MALLOC_UNLOCK;	}	return result;}libc_hidden_def(memalign)#endif
 |