aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc
diff options
context:
space:
mode:
authorlloyd <[email protected]>2012-05-25 22:52:00 +0000
committerlloyd <[email protected]>2012-05-25 22:52:00 +0000
commit12090a7148d9ee73572cc1a7268fc489504a8173 (patch)
tree51e50ce0852c56231e9e6dc13f168b10edd45d01 /src/alloc
parent9594979caf775dc4062850044715b804d1fda60c (diff)
parent65cc04445f8d40497f02a14bd8cb97081790e54b (diff)
propagate from branch 'net.randombit.botan.x509-path-validation' (head 63b5a20eab129ca13287fda33d2d02eec329708f)
to branch 'net.randombit.botan' (head 8b8150f09c55184f028f2929c4e7f7cd0d46d96e)
Diffstat (limited to 'src/alloc')
-rw-r--r--src/alloc/alloc_mmap/info.txt28
-rw-r--r--src/alloc/alloc_mmap/mmap_mem.cpp143
-rw-r--r--src/alloc/alloc_mmap/mmap_mem.h36
-rw-r--r--src/alloc/allocate.h65
-rw-r--r--src/alloc/info.txt1
-rw-r--r--src/alloc/locking_allocator/info.txt1
-rw-r--r--src/alloc/locking_allocator/locking_allocator.cpp236
-rw-r--r--src/alloc/locking_allocator/locking_allocator.h39
-rw-r--r--src/alloc/mem_pool/info.txt12
-rw-r--r--src/alloc/mem_pool/mem_pool.cpp252
-rw-r--r--src/alloc/mem_pool/mem_pool.h77
-rw-r--r--src/alloc/secmem.h439
-rw-r--r--src/alloc/system_alloc/defalloc.cpp103
-rw-r--r--src/alloc/system_alloc/defalloc.h46
-rw-r--r--src/alloc/system_alloc/info.txt13
15 files changed, 366 insertions, 1125 deletions
diff --git a/src/alloc/alloc_mmap/info.txt b/src/alloc/alloc_mmap/info.txt
deleted file mode 100644
index 562277a37..000000000
--- a/src/alloc/alloc_mmap/info.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-define ALLOC_MMAP
-
-<source>
-mmap_mem.cpp
-</source>
-
-<header:internal>
-mmap_mem.h
-</header:internal>
-
-<os>
-linux
-freebsd
-dragonfly
-openbsd
-netbsd
-solaris
-qnx
-darwin
-tru64
-
-# Only without -ansi, otherwise can't get mkstemp
-#cygwin
-</os>
-
-<requires>
-mem_pool
-</requires>
diff --git a/src/alloc/alloc_mmap/mmap_mem.cpp b/src/alloc/alloc_mmap/mmap_mem.cpp
deleted file mode 100644
index e4b602764..000000000
--- a/src/alloc/alloc_mmap/mmap_mem.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
-* Memory Mapping Allocator
-* (C) 1999-2010 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/mmap_mem.h>
-#include <vector>
-#include <cstring>
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#ifndef MAP_FAILED
- #define MAP_FAILED -1
-#endif
-
-namespace Botan {
-
-namespace {
-
-/*
-* MemoryMapping_Allocator Exception
-*/
-class BOTAN_DLL MemoryMapping_Failed : public Exception
- {
- public:
- MemoryMapping_Failed(const std::string& msg) :
- Exception("MemoryMapping_Allocator: " + msg) {}
- };
-
-}
-
-/*
-* Memory Map a File into Memory
-*/
-void* MemoryMapping_Allocator::alloc_block(size_t n)
- {
- class TemporaryFile
- {
- public:
- int get_fd() const { return fd; }
-
- TemporaryFile(const std::string& base)
- {
- const std::string mkstemp_template = base + "XXXXXX";
-
- std::vector<char> filepath(mkstemp_template.begin(),
- mkstemp_template.end());
- filepath.push_back(0); // add terminating NULL
-
- mode_t old_umask = ::umask(077);
- fd = ::mkstemp(&filepath[0]);
- ::umask(old_umask);
-
- if(fd == -1)
- throw MemoryMapping_Failed("Temporary file allocation failed");
-
- if(::unlink(&filepath[0]) != 0)
- throw MemoryMapping_Failed("Could not unlink temporary file");
- }
-
- ~TemporaryFile()
- {
- /*
- * We can safely close here, because post-mmap the file
- * will continue to exist until the mmap is unmapped from
- * our address space upon deallocation (or process exit).
- */
- if(fd != -1 && ::close(fd) == -1)
- throw MemoryMapping_Failed("Could not close file");
- }
- private:
- int fd;
- };
-
- TemporaryFile file("/tmp/botan_");
-
- if(file.get_fd() == -1)
- throw MemoryMapping_Failed("Could not create file");
-
- std::vector<byte> zeros(4096);
-
- size_t remaining = n;
-
- while(remaining)
- {
- const size_t write_try = std::min(zeros.size(), remaining);
-
- ssize_t wrote_got = ::write(file.get_fd(),
- &zeros[0],
- write_try);
-
- if(wrote_got == -1 && errno != EINTR)
- throw MemoryMapping_Failed("Could not write to file");
-
- remaining -= wrote_got;
- }
-
-#ifndef MAP_NOSYNC
- #define MAP_NOSYNC 0
-#endif
-
- void* ptr = ::mmap(0, n,
- PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_NOSYNC,
- file.get_fd(), 0);
-
- if(ptr == static_cast<void*>(MAP_FAILED))
- throw MemoryMapping_Failed("Could not map file");
-
- return ptr;
- }
-
-/*
-* Remove a Memory Mapping
-*/
-void MemoryMapping_Allocator::dealloc_block(void* ptr, size_t n)
- {
- if(ptr == 0)
- return;
-
- const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 };
-
- for(size_t i = 0; i != sizeof(PATTERNS); ++i)
- {
- std::memset(ptr, PATTERNS[i], n);
-
- if(::msync((char*)ptr, n, MS_SYNC))
- throw MemoryMapping_Failed("Sync operation failed");
- }
-
- if(::munmap((char*)ptr, n))
- throw MemoryMapping_Failed("Could not unmap file");
- }
-
-}
diff --git a/src/alloc/alloc_mmap/mmap_mem.h b/src/alloc/alloc_mmap/mmap_mem.h
deleted file mode 100644
index fa4e5e715..000000000
--- a/src/alloc/alloc_mmap/mmap_mem.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-* Memory Mapping Allocator
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_MMAP_ALLOCATOR_H__
-#define BOTAN_MMAP_ALLOCATOR_H__
-
-#include <botan/internal/mem_pool.h>
-
-namespace Botan {
-
-/**
-* Allocator that uses memory maps backed by disk. We zeroize the map
-* upon deallocation. If swap occurs, the VM will swap to the shared
-* file backing rather than to a swap device, which means we know where
-* it is and can zap it later.
-*/
-class MemoryMapping_Allocator : public Pooling_Allocator
- {
- public:
- /**
- * @param mutex used for internal locking
- */
- MemoryMapping_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {}
- std::string type() const { return "mmap"; }
- private:
- void* alloc_block(size_t);
- void dealloc_block(void*, size_t);
- };
-
-}
-
-#endif
diff --git a/src/alloc/allocate.h b/src/alloc/allocate.h
deleted file mode 100644
index b8574be1e..000000000
--- a/src/alloc/allocate.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* Allocator
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_ALLOCATOR_H__
-#define BOTAN_ALLOCATOR_H__
-
-#include <botan/types.h>
-#include <string>
-
-namespace Botan {
-
-/**
-* Allocator Interface
-*/
-class BOTAN_DLL Allocator
- {
- public:
- /**
- * Acquire a pointer to an allocator
- * @param locking is true if the allocator should attempt to
- * secure the memory (eg for using to store keys)
- * @return pointer to an allocator; ownership remains with library,
- * so do not delete
- */
- static Allocator* get(bool locking);
-
- /**
- * Allocate a block of memory
- * @param n how many bytes to allocate
- * @return pointer to n bytes of memory
- */
- virtual void* allocate(size_t n) = 0;
-
- /**
- * Deallocate memory allocated with allocate()
- * @param ptr the pointer returned by allocate()
- * @param n the size of the block pointed to by ptr
- */
- virtual void deallocate(void* ptr, size_t n) = 0;
-
- /**
- * @return name of this allocator type
- */
- virtual std::string type() const = 0;
-
- /**
- * Initialize the allocator
- */
- virtual void init() {}
-
- /**
- * Shutdown the allocator
- */
- virtual void destroy() {}
-
- virtual ~Allocator() {}
- };
-
-}
-
-#endif
diff --git a/src/alloc/info.txt b/src/alloc/info.txt
index 40e7bacdf..0ab7fa768 100644
--- a/src/alloc/info.txt
+++ b/src/alloc/info.txt
@@ -1,4 +1,3 @@
<header:public>
-allocate.h
secmem.h
</header:public>
diff --git a/src/alloc/locking_allocator/info.txt b/src/alloc/locking_allocator/info.txt
new file mode 100644
index 000000000..34877e6bd
--- /dev/null
+++ b/src/alloc/locking_allocator/info.txt
@@ -0,0 +1 @@
+define LOCKING_ALLOCATOR
diff --git a/src/alloc/locking_allocator/locking_allocator.cpp b/src/alloc/locking_allocator/locking_allocator.cpp
new file mode 100644
index 000000000..cc7d24c8d
--- /dev/null
+++ b/src/alloc/locking_allocator/locking_allocator.cpp
@@ -0,0 +1,236 @@
+/*
+* Mlock Allocator
+* (C) 2012 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/locking_allocator.h>
+#include <botan/internal/assert.h>
+#include <algorithm>
+#include <cstring>
+#include <sys/mman.h>
+#include <sys/resource.h>
+
+namespace Botan {
+
+namespace {
+
+size_t mlock_limit()
+ {
+ struct rlimit limits;
+ ::getrlimit(RLIMIT_MEMLOCK, &limits);
+
+ if(limits.rlim_cur < limits.rlim_max)
+ {
+ limits.rlim_cur = limits.rlim_max;
+ ::setrlimit(RLIMIT_MEMLOCK, &limits);
+ ::getrlimit(RLIMIT_MEMLOCK, &limits);
+ }
+
+ /*
+ * Linux defaults to only 64 KiB of mlockable memory per process
+ * (too small) but BSDs offer a small fraction of total RAM (more
+ * than we need). Bound the total mlock size to 256 KiB which is
+ * enough to run the entire test suite without spilling to non-mlock
+ * memory, but small enough that we should not cause problems if
+ * multiple processes are mlocking on the same machine.
+ */
+ return std::min<size_t>(limits.rlim_cur, 256*1024);
+ }
+
+bool ptr_in_pool(const void* pool_ptr, size_t poolsize,
+ const void* buf_ptr, size_t bufsize)
+ {
+ const size_t pool = reinterpret_cast<size_t>(pool_ptr);
+ const size_t buf = reinterpret_cast<size_t>(buf_ptr);
+
+ if(buf < pool || buf >= pool + poolsize)
+ return false;
+
+ BOTAN_ASSERT(buf + bufsize <= pool + poolsize,
+ "Invalid pointer/length halfway into mem pool");
+
+ return true;
+ }
+
+size_t padding_for_alignment(size_t offset, size_t desired_alignment)
+ {
+ size_t mod = offset % desired_alignment;
+ if(mod == 0)
+ return 0; // already right on
+ return desired_alignment - mod;
+ }
+
+}
+
+void* mlock_allocator::allocate(size_t n, size_t alignment)
+ {
+ if(!m_pool || n >= m_poolsize)
+ return nullptr; // bigger than the whole pool!
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ auto best_fit = m_freelist.end();
+
+ for(auto i = m_freelist.begin(); i != m_freelist.end(); ++i)
+ {
+ // If we have a perfect fit, use it immediately
+ if(i->second == n && (i->first % alignment) == 0)
+ {
+ const size_t offset = i->first;
+ m_freelist.erase(i);
+ ::memset(m_pool + offset, 0, n);
+
+ BOTAN_ASSERT((reinterpret_cast<size_t>(m_pool) + offset) % alignment == 0,
+ "Returning correctly aligned pointer");
+
+ return m_pool + offset;
+ }
+
+ if((i->second >= (n + padding_for_alignment(i->first, alignment)) &&
+ ((best_fit == m_freelist.end()) || (best_fit->second > i->second))))
+ {
+ best_fit = i;
+ }
+ }
+
+ if(best_fit != m_freelist.end())
+ {
+ const size_t offset = best_fit->first;
+
+ const size_t alignment_padding = padding_for_alignment(offset, alignment);
+
+ best_fit->first += n + alignment_padding;
+ best_fit->second -= n + alignment_padding;
+
+ // Need to realign, split the block
+ if(alignment_padding)
+ {
+ /*
+ If we used the entire block except for small piece used for
+ alignment at the beginning, so just update the entry already
+ in place (as it is in the correct location), rather than
+ deleting the empty range and inserting the new one in the
+ same location.
+ */
+ if(best_fit->second == 0)
+ {
+ best_fit->first = offset;
+ best_fit->second = alignment_padding;
+ }
+ else
+ m_freelist.insert(best_fit, std::make_pair(offset, alignment_padding));
+ }
+
+ ::memset(m_pool + offset + alignment_padding, 0, n);
+
+ BOTAN_ASSERT((reinterpret_cast<size_t>(m_pool) + offset + alignment_padding) % alignment == 0,
+ "Returning correctly aligned pointer");
+
+ return m_pool + offset + alignment_padding;
+ }
+
+ return nullptr;
+ }
+
+bool mlock_allocator::deallocate(void* p, size_t n)
+ {
+ if(!m_pool || !ptr_in_pool(m_pool, m_poolsize, p, n))
+ return false;
+
+ std::lock_guard<std::mutex> lock(m_mutex);
+
+ const size_t start = static_cast<byte*>(p) - m_pool;
+
+ auto comp = [](std::pair<size_t, size_t> x, std::pair<size_t, size_t> y){ return x.first < y.first; };
+
+ auto i = std::lower_bound(m_freelist.begin(), m_freelist.end(),
+ std::make_pair(start, 0), comp);
+
+ // try to merge with later block
+ if(i != m_freelist.end() && start + n == i->first)
+ {
+ i->first = start;
+ i->second += n;
+ n = 0;
+ }
+
+ // try to merge with previous block
+ if(i != m_freelist.begin())
+ {
+ auto prev = std::prev(i);
+
+ if(prev->first + prev->second == start)
+ {
+ if(n)
+ {
+ prev->second += n;
+ n = 0;
+ }
+ else
+ {
+ // merge adjoining
+ prev->second += i->second;
+ m_freelist.erase(i);
+ }
+ }
+ }
+
+ if(n != 0) // no merge possible?
+ m_freelist.insert(i, std::make_pair(start, n));
+
+ return true;
+ }
+
+mlock_allocator::mlock_allocator() :
+ m_poolsize(mlock_limit()),
+ m_pool(nullptr)
+ {
+#if !defined(MAP_NOCORE)
+ #define MAP_NOCORE 0
+#endif
+
+ if(m_poolsize)
+ {
+ m_pool = static_cast<byte*>(
+ ::mmap(
+ nullptr, m_poolsize,
+ PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_SHARED | MAP_NOCORE,
+ -1, 0));
+
+ if(m_pool == static_cast<byte*>(MAP_FAILED))
+ throw std::runtime_error("Failed to mmap pool");
+
+ std::memset(m_pool, 0x00, m_poolsize);
+
+ if(::mlock(m_pool, m_poolsize) != 0)
+ {
+ ::munmap(m_pool, m_poolsize);
+ m_pool = nullptr;
+ throw std::runtime_error("Failed to lock pool");
+ }
+
+ m_freelist.push_back(std::make_pair(0, m_poolsize));
+ }
+ }
+
+mlock_allocator::~mlock_allocator()
+ {
+ if(m_pool)
+ {
+ std::memset(m_pool, 0, m_poolsize);
+ ::munlock(m_pool, m_poolsize);
+ ::munmap(m_pool, m_poolsize);
+ m_pool = nullptr;
+ }
+ }
+
+mlock_allocator& mlock_allocator::instance()
+ {
+ static mlock_allocator mlock;
+ return mlock;
+ }
+
+}
diff --git a/src/alloc/locking_allocator/locking_allocator.h b/src/alloc/locking_allocator/locking_allocator.h
new file mode 100644
index 000000000..2c756fcd1
--- /dev/null
+++ b/src/alloc/locking_allocator/locking_allocator.h
@@ -0,0 +1,39 @@
+/*
+* Mlock Allocator
+* (C) 2012 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#ifndef BOTAN_MLOCK_ALLOCATOR_H__
+#define BOTAN_MLOCK_ALLOCATOR_H__
+
+#include <botan/types.h>
+#include <vector>
+#include <mutex>
+
+namespace Botan {
+
+class BOTAN_DLL mlock_allocator
+ {
+ public:
+ static mlock_allocator& instance();
+
+ void* allocate(size_t n, size_t alignment);
+
+ bool deallocate(void* p, size_t n);
+
+ private:
+ mlock_allocator();
+
+ ~mlock_allocator();
+
+ std::mutex m_mutex;
+ size_t m_poolsize;
+ std::vector<std::pair<size_t, size_t>> m_freelist;
+ byte* m_pool;
+ };
+
+}
+
+#endif
diff --git a/src/alloc/mem_pool/info.txt b/src/alloc/mem_pool/info.txt
deleted file mode 100644
index 5097c325f..000000000
--- a/src/alloc/mem_pool/info.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-
-<source>
-mem_pool.cpp
-</source>
-
-<header:internal>
-mem_pool.h
-</header:internal>
-
-<requires>
-mutex
-</requires>
diff --git a/src/alloc/mem_pool/mem_pool.cpp b/src/alloc/mem_pool/mem_pool.cpp
deleted file mode 100644
index f32eb9604..000000000
--- a/src/alloc/mem_pool/mem_pool.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
-* Pooling Allocator
-* (C) 1999-2008 Jack Lloyd
-* 2005 Matthew Gregan
-* 2005-2006 Matt Johnston
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/mem_pool.h>
-#include <botan/internal/rounding.h>
-#include <botan/mem_ops.h>
-#include <algorithm>
-#include <exception>
-
-namespace Botan {
-
-/*
-* Memory_Block Constructor
-*/
-Pooling_Allocator::Memory_Block::Memory_Block(void* buf)
- {
- buffer = static_cast<byte*>(buf);
- bitmap = 0;
- buffer_end = buffer + (BLOCK_SIZE * BITMAP_SIZE);
- }
-
-/*
-* See if ptr is contained by this block
-*/
-bool Pooling_Allocator::Memory_Block::contains(void* ptr,
- size_t length) const
- {
- return ((buffer <= ptr) &&
- (buffer_end >= static_cast<byte*>(ptr) + length * BLOCK_SIZE));
- }
-
-/*
-* Allocate some memory, if possible
-*/
-byte* Pooling_Allocator::Memory_Block::alloc(size_t n)
- {
- if(n == 0 || n > BITMAP_SIZE)
- return 0;
-
- if(n == BITMAP_SIZE)
- {
- if(bitmap)
- return 0;
- else
- {
- bitmap = ~bitmap;
- return buffer;
- }
- }
-
- bitmap_type mask = (static_cast<bitmap_type>(1) << n) - 1;
- size_t offset = 0;
-
- while(bitmap & mask)
- {
- mask <<= 1;
- ++offset;
-
- if((bitmap & mask) == 0)
- break;
- if(mask >> 63)
- break;
- }
-
- if(bitmap & mask)
- return 0;
-
- bitmap |= mask;
- return buffer + offset * BLOCK_SIZE;
- }
-
-/*
-* Mark this memory as free, if we own it
-*/
-void Pooling_Allocator::Memory_Block::free(void* ptr, size_t blocks)
- {
- clear_mem(static_cast<byte*>(ptr), blocks * BLOCK_SIZE);
-
- const size_t offset = (static_cast<byte*>(ptr) - buffer) / BLOCK_SIZE;
-
- if(offset == 0 && blocks == BITMAP_SIZE)
- bitmap = ~bitmap;
- else
- {
- for(size_t j = 0; j != blocks; ++j)
- bitmap &= ~(static_cast<bitmap_type>(1) << (j+offset));
- }
- }
-
-/*
-* Pooling_Allocator Constructor
-*/
-Pooling_Allocator::Pooling_Allocator(Mutex* m) : mutex(m)
- {
- last_used = blocks.begin();
- }
-
-/*
-* Pooling_Allocator Destructor
-*/
-Pooling_Allocator::~Pooling_Allocator()
- {
- delete mutex;
- if(blocks.size())
- throw Invalid_State("Pooling_Allocator: Never released memory");
- }
-
-/*
-* Free all remaining memory
-*/
-void Pooling_Allocator::destroy()
- {
- Mutex_Holder lock(mutex);
-
- blocks.clear();
-
- for(size_t j = 0; j != allocated.size(); ++j)
- dealloc_block(allocated[j].first, allocated[j].second);
- allocated.clear();
- }
-
-/*
-* Allocation
-*/
-void* Pooling_Allocator::allocate(size_t n)
- {
- const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
- const size_t BLOCK_SIZE = Memory_Block::block_size();
-
- Mutex_Holder lock(mutex);
-
- if(n <= BITMAP_SIZE * BLOCK_SIZE)
- {
- const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE;
-
- byte* mem = allocate_blocks(block_no);
- if(mem)
- return mem;
-
- get_more_core(BOTAN_MEM_POOL_CHUNK_SIZE);
-
- mem = allocate_blocks(block_no);
- if(mem)
- return mem;
-
- throw Memory_Exhaustion();
- }
-
- void* new_buf = alloc_block(n);
- if(new_buf)
- return new_buf;
-
- throw Memory_Exhaustion();
- }
-
-/*
-* Deallocation
-*/
-void Pooling_Allocator::deallocate(void* ptr, size_t n)
- {
- const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
- const size_t BLOCK_SIZE = Memory_Block::block_size();
-
- if(ptr == 0 && n == 0)
- return;
-
- Mutex_Holder lock(mutex);
-
- if(n > BITMAP_SIZE * BLOCK_SIZE)
- dealloc_block(ptr, n);
- else
- {
- const size_t block_no = round_up(n, BLOCK_SIZE) / BLOCK_SIZE;
-
- std::vector<Memory_Block>::iterator i =
- std::lower_bound(blocks.begin(), blocks.end(), Memory_Block(ptr));
-
- if(i == blocks.end() || !i->contains(ptr, block_no))
- throw Invalid_State("Pointer released to the wrong allocator");
-
- i->free(ptr, block_no);
- }
- }
-
-/*
-* Try to get some memory from an existing block
-*/
-byte* Pooling_Allocator::allocate_blocks(size_t n)
- {
- if(blocks.empty())
- return 0;
-
- std::vector<Memory_Block>::iterator i = last_used;
-
- do
- {
- byte* mem = i->alloc(n);
- if(mem)
- {
- last_used = i;
- return mem;
- }
-
- ++i;
- if(i == blocks.end())
- i = blocks.begin();
- }
- while(i != last_used);
-
- return 0;
- }
-
-/*
-* Allocate more memory for the pool
-*/
-void Pooling_Allocator::get_more_core(size_t in_bytes)
- {
- const size_t BITMAP_SIZE = Memory_Block::bitmap_size();
- const size_t BLOCK_SIZE = Memory_Block::block_size();
-
- const size_t TOTAL_BLOCK_SIZE = BLOCK_SIZE * BITMAP_SIZE;
-
- // upper bound on allocation is 1 MiB
- in_bytes = std::min<size_t>(in_bytes, 1024 * 1024);
-
- const size_t in_blocks = round_up(in_bytes, BLOCK_SIZE) / TOTAL_BLOCK_SIZE;
- const size_t to_allocate = in_blocks * TOTAL_BLOCK_SIZE;
-
- void* ptr = alloc_block(to_allocate);
- if(ptr == 0)
- throw Memory_Exhaustion();
-
- allocated.push_back(std::make_pair(ptr, to_allocate));
-
- for(size_t j = 0; j != in_blocks; ++j)
- {
- byte* byte_ptr = static_cast<byte*>(ptr);
- blocks.push_back(Memory_Block(byte_ptr + j * TOTAL_BLOCK_SIZE));
- }
-
- std::sort(blocks.begin(), blocks.end());
- last_used = std::lower_bound(blocks.begin(), blocks.end(),
- Memory_Block(ptr));
- }
-
-}
diff --git a/src/alloc/mem_pool/mem_pool.h b/src/alloc/mem_pool/mem_pool.h
deleted file mode 100644
index 28d4dd903..000000000
--- a/src/alloc/mem_pool/mem_pool.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* Pooling Allocator
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_POOLING_ALLOCATOR_H__
-#define BOTAN_POOLING_ALLOCATOR_H__
-
-#include <botan/allocate.h>
-#include <botan/exceptn.h>
-#include <botan/internal/mutex.h>
-#include <utility>
-#include <vector>
-
-namespace Botan {
-
-/**
-* Pooling Allocator
-*/
-class Pooling_Allocator : public Allocator
- {
- public:
- void* allocate(size_t);
- void deallocate(void*, size_t);
-
- void destroy();
-
- /**
- * @param mutex used for internal locking
- */
- Pooling_Allocator(Mutex* mutex);
- ~Pooling_Allocator();
- private:
- void get_more_core(size_t);
- byte* allocate_blocks(size_t);
-
- virtual void* alloc_block(size_t) = 0;
- virtual void dealloc_block(void*, size_t) = 0;
-
- class Memory_Block
- {
- public:
- Memory_Block(void*);
-
- static size_t bitmap_size() { return BITMAP_SIZE; }
- static size_t block_size() { return BLOCK_SIZE; }
-
- bool contains(void*, size_t) const;
- byte* alloc(size_t);
- void free(void*, size_t);
-
- bool operator<(const Memory_Block& other) const
- {
- if(buffer < other.buffer && other.buffer < buffer_end)
- return false;
- return (buffer < other.buffer);
- }
- private:
- typedef u64bit bitmap_type;
- static const size_t BITMAP_SIZE = 8 * sizeof(bitmap_type);
- static const size_t BLOCK_SIZE = 64;
-
- bitmap_type bitmap;
- byte* buffer, *buffer_end;
- };
-
- std::vector<Memory_Block> blocks;
- std::vector<Memory_Block>::iterator last_used;
- std::vector<std::pair<void*, size_t> > allocated;
- Mutex* mutex;
- };
-
-}
-
-#endif
diff --git a/src/alloc/secmem.h b/src/alloc/secmem.h
index 6c8a75c44..739ba63a5 100644
--- a/src/alloc/secmem.h
+++ b/src/alloc/secmem.h
@@ -1,6 +1,6 @@
/*
* Secure Memory Buffers
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2012 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/
@@ -8,369 +8,121 @@
#ifndef BOTAN_SECURE_MEMORY_BUFFERS_H__
#define BOTAN_SECURE_MEMORY_BUFFERS_H__
-#include <botan/allocate.h>
#include <botan/mem_ops.h>
#include <algorithm>
+#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
+ #include <botan/locking_allocator.h>
+#endif
+
namespace Botan {
-/**
-* This class represents variable length memory buffers.
-*/
template<typename T>
-class MemoryRegion
+class secure_allocator
{
public:
- /**
- * Find out the size of the buffer, i.e. how many objects of type T it
- * contains.
- * @return size of the buffer
- */
- size_t size() const { return used; }
-
- /**
- * Find out whether this buffer is empty.
- * @return true if the buffer is empty, false otherwise
- */
- bool empty() const { return (used == 0); }
-
- /**
- * Get a pointer to the first element in the buffer.
- * @return pointer to the first element in the buffer
- */
- operator T* () { return buf; }
-
- /**
- * Get a constant pointer to the first element in the buffer.
- * @return constant pointer to the first element in the buffer
- */
- operator const T* () const { return buf; }
-
- /**
- * Get a pointer to the first element in the buffer.
- * @return pointer to the first element in the buffer
- */
- T* begin() { return buf; }
-
- /**
- * Get a constant pointer to the first element in the buffer.
- * @return constant pointer to the first element in the buffer
- */
- const T* begin() const { return buf; }
-
- /**
- * Get a pointer to the last element in the buffer.
- * @return pointer to the last element in the buffer
- */
- T* end() { return (buf + size()); }
-
- /**
- * Get a constant pointer to the last element in the buffer.
- * @return constant pointer to the last element in the buffer
- */
- const T* end() const { return (buf + size()); }
-
- /**
- * Check two buffers for equality.
- * @return true iff the content of both buffers is byte-wise equal
- */
- bool operator==(const MemoryRegion<T>& other) const
- {
- return (size() == other.size() &&
- same_mem(buf, other.buf, size()));
- }
+ typedef T value_type;
- /**
- * Compare two buffers
- * @return true iff this is ordered before other
- */
- bool operator<(const MemoryRegion<T>& other) const;
-
- /**
- * Check two buffers for inequality.
- * @return false if the content of both buffers is byte-wise equal, true
- * otherwise.
- */
- bool operator!=(const MemoryRegion<T>& other) const
- { return (!(*this == other)); }
-
- /**
- * Copy the contents of another buffer into this buffer.
- * The former contents of *this are discarded.
- * @param other the buffer to copy the contents from.
- * @return reference to *this
- */
- MemoryRegion<T>& operator=(const MemoryRegion<T>& other)
- {
- if(this != &other)
- {
- this->resize(other.size());
- this->copy(&other[0], other.size());
- }
- return (*this);
- }
+ typedef T* pointer;
+ typedef const T* const_pointer;
+
+ typedef T& reference;
+ typedef const T& const_reference;
- /**
- * Copy the contents of an array of objects of type T into this buffer.
- * The former contents of *this are discarded.
- * The length of *this must be at least n, otherwise memory errors occur.
- * @param in the array to copy the contents from
- * @param n the length of in
- */
- void copy(const T in[], size_t n)
+ typedef std::size_t size_type;
+ typedef std::ptrdiff_t difference_type;
+
+ secure_allocator() noexcept {}
+
+ ~secure_allocator() noexcept {}
+
+ pointer address(reference x) const noexcept
+ { return std::addressof(x); }
+
+ const_pointer address(const_reference x) const noexcept
+ { return std::addressof(x); }
+
+ pointer allocate(size_type n, const void* = 0)
{
- copy_mem(buf, in, std::min(n, size()));
+#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
+ if(pointer p = static_cast<pointer>(mlock_allocator::instance().allocate(n*sizeof(T), sizeof(T))))
+ return p;
+#endif
+
+ pointer p = new T[n];
+ clear_mem(p, n);
+ return p;
}
- /**
- * Copy the contents of an array of objects of type T into this buffer.
- * The former contents of *this are discarded.
- * The length of *this must be at least n, otherwise memory errors occur.
- * @param off the offset position inside this buffer to start inserting
- * the copied bytes
- * @param in the array to copy the contents from
- * @param n the length of in
- */
- void copy(size_t off, const T in[], size_t n)
+ void deallocate(pointer p, size_type n)
{
- copy_mem(buf + off, in, std::min(n, size() - off));
+ clear_mem(p, n);
+
+#if defined(BOTAN_HAS_LOCKING_ALLOCATOR)
+ if(mlock_allocator::instance().deallocate(p, n*sizeof(T)))
+ return;
+#endif
+
+ delete [] p;
}
- /**
- * Append a single element.
- * @param x the element to append
- */
- void push_back(T x)
+ size_type max_size() const noexcept
{
- resize(size() + 1);
- buf[size()-1] = x;
+ return static_cast<size_type>(-1) / sizeof(T);
}
- /**
- * Reset this buffer to an empty buffer with size zero.
- */
- void clear() { resize(0); }
-
- /**
- * Inserts or erases elements at the end such that the size
- * becomes n, leaving elements in the range 0...n unmodified if
- * set or otherwise zero-initialized
- * @param n length of the new buffer
- */
- void resize(size_t n);
-
- /**
- * Swap this buffer with another object.
- */
- void swap(MemoryRegion<T>& other);
-
- virtual ~MemoryRegion() { deallocate(buf, allocated); }
- protected:
- MemoryRegion() : buf(0), used(0), allocated(0), alloc(0) {}
-
- /**
- * Copy constructor
- * @param other the other region to copy
- */
- MemoryRegion(const MemoryRegion<T>& other)
+ template<typename U, typename... Args>
+ void construct(U* p, Args&&... args)
{
- buf = 0;
- used = allocated = 0;
- alloc = other.alloc;
- resize(other.size());
- copy(&other[0], other.size());
+ ::new(static_cast<void*>(p)) U(std::forward<Args>(args)...);
}
- /**
- * @param locking should we use a locking allocator
- * @param length the initial length to use
- */
- void init(bool locking, size_t length = 0)
- { alloc = Allocator::get(locking); resize(length); }
+ template<typename U> void destroy(U* p) { p->~U(); }
+ };
- private:
- T* allocate(size_t n)
- {
- return static_cast<T*>(alloc->allocate(sizeof(T)*n));
- }
+template<typename T> inline bool
+operator==(const secure_allocator<T>&, const secure_allocator<T>&)
+ { return true; }
- void deallocate(T* p, size_t n)
- { if(alloc && p && n) alloc->deallocate(p, sizeof(T)*n); }
+template<typename T> inline bool
+operator!=(const secure_allocator<T>&, const secure_allocator<T>&)
+ { return false; }
- T* buf;
- size_t used;
- size_t allocated;
- Allocator* alloc;
- };
+template<typename T> using secure_vector = std::vector<T, secure_allocator<T>>;
-/*
-* Change the size of the buffer
-*/
template<typename T>
-void MemoryRegion<T>::resize(size_t n)
+std::vector<T> unlock(const secure_vector<T>& in)
{
- if(n <= allocated)
- {
- size_t zap = std::min(used, n);
- clear_mem(buf + zap, allocated - zap);
- used = n;
- }
- else
- {
- T* new_buf = allocate(n);
- copy_mem(new_buf, buf, used);
- deallocate(buf, allocated);
- buf = new_buf;
- allocated = used = n;
- }
+ std::vector<T> out(in.size());
+ copy_mem(&out[0], &in[0], in.size());
+ return out;
}
-/*
-* Compare this buffer with another one
-*/
-template<typename T>
-bool MemoryRegion<T>::operator<(const MemoryRegion<T>& other) const
+template<typename T, typename Alloc>
+size_t buffer_insert(std::vector<T, Alloc>& buf,
+ size_t buf_offset,
+ const T input[],
+ size_t input_length)
{
- const size_t min_size = std::min(size(), other.size());
-
- // This should probably be rewritten to run in constant time
- for(size_t i = 0; i != min_size; ++i)
- {
- if(buf[i] < other[i])
- return true;
- if(buf[i] > other[i])
- return false;
- }
-
- // First min_size bytes are equal, shorter is first
- return (size() < other.size());
+ const size_t to_copy = std::min(input_length, buf.size() - buf_offset);
+ copy_mem(&buf[buf_offset], input, to_copy);
+ return to_copy;
}
-/*
-* Swap this buffer with another one
-*/
-template<typename T>
-void MemoryRegion<T>::swap(MemoryRegion<T>& x)
+template<typename T, typename Alloc, typename Alloc2>
+size_t buffer_insert(std::vector<T, Alloc>& buf,
+ size_t buf_offset,
+ const std::vector<T, Alloc2>& input)
{
- std::swap(buf, x.buf);
- std::swap(used, x.used);
- std::swap(allocated, x.allocated);
- std::swap(alloc, x.alloc);
+ const size_t to_copy = std::min(input.size(), buf.size() - buf_offset);
+ copy_mem(&buf[buf_offset], &input[0], to_copy);
+ return to_copy;
}
-/**
-* This class represents variable length buffers that do not
-* make use of memory locking.
-*/
-template<typename T>
-class MemoryVector : public MemoryRegion<T>
- {
- public:
- /**
- * Copy the contents of another buffer into this buffer.
- * @param in the buffer to copy the contents from
- * @return reference to *this
- */
- MemoryVector<T>& operator=(const MemoryRegion<T>& in)
- {
- if(this != &in)
- {
- this->resize(in.size());
- this->copy(&in[0], in.size());
- }
- return (*this);
- }
-
- /**
- * Create a buffer of the specified length.
- * @param n the length of the buffer to create.
- */
- MemoryVector(size_t n = 0) { this->init(false, n); }
-
- /**
- * Create a buffer with the specified contents.
- * @param in the array containing the data to be initially copied
- * into the newly created buffer
- * @param n the size of the arry in
- */
- MemoryVector(const T in[], size_t n)
- {
- this->init(false);
- this->resize(n);
- this->copy(in, n);
- }
-
- /**
- * Copy constructor.
- */
- MemoryVector(const MemoryRegion<T>& in)
- {
- this->init(false);
- this->resize(in.size());
- this->copy(&in[0], in.size());
- }
- };
-
-/**
-* This class represents variable length buffers using the operating
-* systems capability to lock memory, i.e. keeping it from being
-* swapped out to disk. In this way, a security hole allowing attackers
-* to find swapped out secret keys is closed.
-*/
-template<typename T>
-class SecureVector : public MemoryRegion<T>
- {
- public:
- /**
- * Copy the contents of another buffer into this buffer.
- * @param other the buffer to copy the contents from
- * @return reference to *this
- */
- SecureVector<T>& operator=(const MemoryRegion<T>& other)
- {
- if(this != &other)
- {
- this->resize(other.size());
- this->copy(&other[0], other.size());
- }
- return (*this);
- }
-
- /**
- * Create a buffer of the specified length.
- * @param n the length of the buffer to create.
- */
- SecureVector(size_t n = 0) { this->init(true, n); }
-
- /**
- * Create a buffer with the specified contents.
- * @param in the array containing the data to be initially copied
- * into the newly created buffer
- * @param n the size of the array in
- */
- SecureVector(const T in[], size_t n)
- {
- this->init(true);
- this->resize(n);
- this->copy(&in[0], n);
- }
-
- /**
- * Create a buffer with contents specified contents.
- * @param in the buffer holding the contents that will be
- * copied into the newly created buffer.
- */
- SecureVector(const MemoryRegion<T>& in)
- {
- this->init(true);
- this->resize(in.size());
- this->copy(&in[0], in.size());
- }
- };
-
-template<typename T>
-MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
- const MemoryRegion<T>& in)
+template<typename T, typename Alloc, typename Alloc2>
+std::vector<T, Alloc>&
+operator+=(std::vector<T, Alloc>& out,
+ const std::vector<T, Alloc2>& in)
{
const size_t copy_offset = out.size();
out.resize(out.size() + in.size());
@@ -378,17 +130,16 @@ MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
return out;
}
-template<typename T>
-MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
- T in)
+template<typename T, typename Alloc>
+std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out, T in)
{
out.push_back(in);
return out;
}
-template<typename T, typename L>
-MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
- const std::pair<const T*, L>& in)
+template<typename T, typename Alloc, typename L>
+std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out,
+ const std::pair<const T*, L>& in)
{
const size_t copy_offset = out.size();
out.resize(out.size() + in.second);
@@ -396,9 +147,9 @@ MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
return out;
}
-template<typename T, typename L>
-MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
- const std::pair<T*, L>& in)
+template<typename T, typename Alloc, typename L>
+std::vector<T, Alloc>& operator+=(std::vector<T, Alloc>& out,
+ const std::pair<T*, L>& in)
{
const size_t copy_offset = out.size();
out.resize(out.size() + in.second);
@@ -410,22 +161,12 @@ MemoryRegion<T>& operator+=(MemoryRegion<T>& out,
* Zeroise the values; length remains unchanged
* @param vec the vector to zeroise
*/
-template<typename T>
-void zeroise(MemoryRegion<T>& vec)
+template<typename T, typename Alloc>
+void zeroise(std::vector<T, Alloc>& vec)
{
clear_mem(&vec[0], vec.size());
}
}
-namespace std {
-
-template<typename T>
-inline void swap(Botan::MemoryRegion<T>& x, Botan::MemoryRegion<T>& y)
- {
- x.swap(y);
- }
-
-}
-
#endif
diff --git a/src/alloc/system_alloc/defalloc.cpp b/src/alloc/system_alloc/defalloc.cpp
deleted file mode 100644
index 8e178bb14..000000000
--- a/src/alloc/system_alloc/defalloc.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-* Basic Allocators
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#include <botan/internal/defalloc.h>
-#include <botan/internal/mlock.h>
-#include <botan/libstate.h>
-#include <cstdlib>
-#include <cstring>
-
-namespace Botan {
-
-namespace {
-
-/*
-* Perform Memory Allocation
-*/
-void* do_malloc(size_t n, bool do_lock)
- {
- void* ptr = std::malloc(n);
-
- if(!ptr)
- return 0;
-
- if(do_lock)
- lock_mem(ptr, n);
-
- std::memset(ptr, 0, n);
- return ptr;
- }
-
-/*
-* Perform Memory Deallocation
-*/
-void do_free(void* ptr, size_t n, bool do_lock)
- {
- if(!ptr)
- return;
-
- std::memset(ptr, 0, n);
- if(do_lock)
- unlock_mem(ptr, n);
-
- std::free(ptr);
- }
-
-}
-
-/*
-* Malloc_Allocator's Allocation
-*/
-void* Malloc_Allocator::allocate(size_t n)
- {
- void* ptr = do_malloc(n, false);
- if(!ptr)
- throw Memory_Exhaustion();
- return ptr;
- }
-
-/*
-* Malloc_Allocator's Deallocation
-*/
-void Malloc_Allocator::deallocate(void* ptr, size_t n)
- {
- do_free(ptr, n, false);
- }
-
-/*
-* Locking_Allocator's Allocation
-*/
-void* Locking_Allocator::alloc_block(size_t n)
- {
- return do_malloc(n, true);
- }
-
-/*
-* Locking_Allocator's Deallocation
-*/
-void Locking_Allocator::dealloc_block(void* ptr, size_t n)
- {
- do_free(ptr, n, true);
- }
-
-/*
-* Get an allocator
-*/
-Allocator* Allocator::get(bool locking)
- {
- std::string type = "";
- if(!locking)
- type = "malloc";
-
- Allocator* alloc = global_state().get_allocator(type);
- if(alloc)
- return alloc;
-
- throw Internal_Error("Couldn't find an allocator to use in get_allocator");
- }
-
-}
diff --git a/src/alloc/system_alloc/defalloc.h b/src/alloc/system_alloc/defalloc.h
deleted file mode 100644
index 6fba0e511..000000000
--- a/src/alloc/system_alloc/defalloc.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-* Basic Allocators
-* (C) 1999-2007 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-#ifndef BOTAN_BASIC_ALLOC_H__
-#define BOTAN_BASIC_ALLOC_H__
-
-#include <botan/internal/mem_pool.h>
-
-namespace Botan {
-
-/**
-* Allocator using malloc
-*/
-class Malloc_Allocator : public Allocator
- {
- public:
- void* allocate(size_t);
- void deallocate(void*, size_t);
-
- std::string type() const { return "malloc"; }
- };
-
-/**
-* Allocator using malloc plus locking
-*/
-class Locking_Allocator : public Pooling_Allocator
- {
- public:
- /**
- * @param mutex used for internal locking
- */
- Locking_Allocator(Mutex* mutex) : Pooling_Allocator(mutex) {}
-
- std::string type() const { return "locking"; }
- private:
- void* alloc_block(size_t);
- void dealloc_block(void*, size_t);
- };
-
-}
-
-#endif
diff --git a/src/alloc/system_alloc/info.txt b/src/alloc/system_alloc/info.txt
deleted file mode 100644
index 87de0cb67..000000000
--- a/src/alloc/system_alloc/info.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-
-<source>
-defalloc.cpp
-</source>
-
-<header:internal>
-defalloc.h
-</header:internal>
-
-<requires>
-libstate
-mem_pool
-</requires>