1/*
2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// cssmalloc - memory allocation in the CDSA world.
27//
28// Don't eat heavily before inspecting this code.
29//
30#include <security_utilities/alloc.h>
31#include <security_utilities/memutils.h>
32#include <security_utilities/globalizer.h>
33#include <stdlib.h>
34#include <errno.h>
35
36using LowLevelMemoryUtilities::alignof;
37using LowLevelMemoryUtilities::increment;
38using LowLevelMemoryUtilities::alignUp;
39
40extern "C" size_t malloc_size(void *);
41
42
43//
44// Features of the Allocator root class
45//
46bool Allocator::operator == (const Allocator &alloc) const throw()
47{
48	return this == &alloc;
49}
50
51Allocator::~Allocator()
52{
53}
54
55
56//
57// Standard Allocator variants.
58// Note that all calls to Allocator::standard(xxx) with the same xxx argument
59// must produce compatible allocators (i.e. they must be work on a common memory
60// pool). This is trivially achieved here by using singletons.
61//
62struct DefaultAllocator : public Allocator {
63	void *malloc(size_t size) throw(std::bad_alloc);
64	void free(void *addr) throw();
65	void *realloc(void *addr, size_t size) throw(std::bad_alloc);
66};
67
68struct SensitiveAllocator : public DefaultAllocator {
69    void free(void *addr) throw();
70    void *realloc(void *addr, size_t size) throw(std::bad_alloc);
71};
72
73struct DefaultAllocators {
74    DefaultAllocator standard;
75    SensitiveAllocator sensitive;
76};
77
78static ModuleNexus<DefaultAllocators> defaultAllocators;
79
80
81Allocator &Allocator::standard(UInt32 request)
82{
83    switch (request) {
84    case normal:
85        return defaultAllocators().standard;
86    case sensitive:
87        return defaultAllocators().sensitive;
88    default:
89        UnixError::throwMe(ENOMEM);
90    }
91}
92
93void *DefaultAllocator::malloc(size_t size) throw(std::bad_alloc)
94{
95	if (void *result = ::malloc(size))
96		return result;
97	throw std::bad_alloc();
98}
99
100void DefaultAllocator::free(void *addr) throw()
101{
102	::free(addr);
103}
104
105void *DefaultAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc)
106{
107	if (void *result = ::realloc(addr, newSize))
108		return result;
109	throw std::bad_alloc();
110}
111
112void SensitiveAllocator::free(void *addr) throw()
113{
114    memset(addr, 0, malloc_size(addr));
115    DefaultAllocator::free(addr);
116}
117
118void *SensitiveAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc)
119{
120    size_t oldSize = malloc_size(addr);
121    if (newSize < oldSize)
122        memset(increment(addr, newSize), 0, oldSize - newSize);
123    return DefaultAllocator::realloc(addr, newSize);
124}
125
126
127//
128// Memory allocators for CssmHeap objects.
129// This implementation stores a pointer to the allocator used into memory
130// *after* the object's proper storage block. This allows the usual free()
131// functions to safely free our (hidden) pointer without knowing about it.
132// An allocator argument of NULL is interpreted as the standard allocator.
133//
134void *CssmHeap::operator new (size_t size, Allocator *alloc) throw(std::bad_alloc)
135{
136	if (alloc == NULL)
137		alloc = &Allocator::standard();
138	size = alignUp(size, alignof<Allocator *>());
139	size_t totalSize = size + sizeof(Allocator *);
140	void *addr = alloc->malloc(totalSize);
141	*(Allocator **)increment(addr, size) = alloc;
142	return addr;
143}
144
145void CssmHeap::operator delete (void *addr, size_t size, Allocator *alloc) throw()
146{
147	alloc->free(addr);	// as per C++ std, called (only) if construction fails
148}
149
150void CssmHeap::operator delete (void *addr, size_t size) throw()
151{
152	void *end = increment(addr, alignUp(size, alignof<Allocator *>()));
153	(*(Allocator **)end)->free(addr);
154}
155
156
157//
158// CssmVector
159//
160