├── .gitignore ├── CMakeLists.txt ├── CONTRIBUTORS ├── LICENSE ├── Makefile ├── README.md ├── _config.yml ├── doc ├── artifacts_available.jpg ├── artifacts_evaluated_functional.jpg ├── logo.png ├── overview.png ├── pcg32-license.txt └── slides │ ├── Makefile │ ├── Presentation.md │ ├── include │ ├── CVE.pdf │ ├── Readme.md │ ├── TLSF.pdf │ ├── artifacts_available.jpg │ ├── artifacts_evaluated_functional.jpg │ ├── artifacts_evaluated_reusable.jpg │ ├── bibop_heap.png │ ├── buffer_overflow.png │ ├── design-space.pdf │ ├── entropy-mem.pdf │ ├── entropy-time.pdf │ ├── gp-ratio.pdf │ ├── init.pdf │ ├── inline_metadata.png │ ├── macro-mem.pdf │ ├── macro-time.pdf │ ├── multithreading.pdf │ ├── overview.odg │ ├── overview.pdf │ ├── overview1.pdf │ ├── overview2.pdf │ ├── overview3.pdf │ ├── table-features.odt │ └── table-features.pdf │ ├── slimguard.pdf │ └── slimguard.tex ├── include ├── debug.h ├── slimguard-large.h ├── slimguard-mmap.h ├── slimguard.h └── sll.h ├── index.md ├── src ├── CMakeLists.txt ├── gnuwrapper.cpp ├── slimguard-large.c ├── slimguard-mmap.c ├── slimguard.c └── sll.c └── test ├── CMakeLists.txt ├── calloc.c ├── catch.hpp ├── large-alloc.c ├── malloc-test.c ├── memalign-free.c ├── memalign-standalone ├── .gdb_history ├── Makefile └── memalign.c ├── memalign.c ├── memory-content.c ├── mimalloc-test.c ├── realloc.c ├── slimguard-large-test.c ├── slimguard-test.c └── very-large.c /.gitignore: -------------------------------------------------------------------------------- 1 | libSlimGuard.so 2 | build 3 | test/mimalloc/test-stress 4 | test/malloc-test/malloc-test 5 | slimguard-standalone.c 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7.2) # CMake version check 2 | project(SlimGuard) 3 | 4 | add_subdirectory(src) 5 | add_subdirectory(test) 6 | enable_testing() 7 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | Beichen Liu , Teledyne Lecroy Frontline Inc. 2 | Pierre Olivier , The University of Manchester 3 | Eric Meisner , TrustLeap.com 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Systems Software Research Group @ Virginia Tech 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGETS = libSlimGuard.so 2 | CC = gcc 3 | CXX = g++ 4 | STANDALONE=slimguard-standalone 5 | 6 | CFLAGS = -Wall -pedantic -O3 -Wno-deprecated-declarations -I./include 7 | 8 | CFLAGS += -DGUARDPAGE 9 | CFLAGS += -DRELEASE_MEM 10 | # CFLAGS += -DDESTROY_ON_FREE 11 | CFLAGS += -DUSE_CANARY 12 | # CFLAGS += -DDEBUG 13 | 14 | 15 | all: $(TARGETS) 16 | 17 | libSlimGuard.so: 18 | $(CC) $(CFLAGS) -o $@ src/gnuwrapper.cpp $(wildcard src/*.c) -shared -fPIC $(LDFLAGS) 19 | 20 | standalone: 21 | rm -rf $(STANDALONE).c 22 | sed "s/#include \"/\/\/ #include \"/" include/*.h >> $(STANDALONE).c 23 | sed "s/#include \"/\/\/ #include \"/" src/slimguard.c >> $(STANDALONE).c 24 | sed "s/#include \"/\/\/ #include \"/" src/slimguard-large.c >> $(STANDALONE).c 25 | sed "s/#include \"/\/\/ #include \"/" src/slimguard-mmap.c >> $(STANDALONE).c 26 | sed "s/#include \"/\/\/ #include \"/" src/sll.c >> $(STANDALONE).c 27 | echo "" >> $(STANDALONE).c 28 | echo " int main(int argc, char **argv) {" >> $(STANDALONE).c 29 | echo " int num = 1000000;" >> $(STANDALONE).c 30 | echo " void *ptr[num];" >> $(STANDALONE).c 31 | echo "" >> $(STANDALONE).c 32 | echo " for (int i = 0; i < num; i++) {" >> $(STANDALONE).c 33 | echo " int size = rand()%1024;" >> $(STANDALONE).c 34 | echo " ptr[i] = xxmalloc(size);" >> $(STANDALONE).c 35 | echo " assert(ptr[i]);" >> $(STANDALONE).c 36 | echo " memset(ptr[i], 0x0, size);" >> $(STANDALONE).c 37 | echo " }" >> $(STANDALONE).c 38 | echo "" >> $(STANDALONE).c 39 | echo " for (int i = (num-1); i >= 0; i--) {" >> $(STANDALONE).c 40 | echo " xxfree(ptr[i]);" $(STANDALONE).c 41 | echo " }" >> $(STANDALONE).c 42 | echo "" >> $(STANDALONE).c 43 | echo "return 0;" >> $(STANDALONE).c 44 | echo "}" >> $(STANDALONE).c 45 | 46 | clean: 47 | $(RM) $(TARGETS) *.o 48 | 49 | .PHONY: all clean 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SlimGuard: A Secure and Memory-Efficient Heap Allocator 2 | 3 | SlimGuard is a secure dynamic memory allocator whose design is driven by memory 4 | efficiency. We redesign the security features of state-of-the-art allocators 5 | with memory efficiency in mind. SlimGuard protects against widespread heap-related 6 | attacks such as overflows, over-reads, double/invalid free, and use-after-free. 7 | Among other features, SlimGuard uses an efficient fine-grain size classes indexing 8 | mechanism and implements a novel dynamic canary scheme optimized for memory 9 | overhead reduction. 10 | 11 | #### Build SlimGuard 12 | 13 | SlimGuard can be built on most modern Linux distributions and has been tested on 14 | Ubuntu 18.04 and Debian 10. 15 | 16 | To build SlimGuard, run ```make``` in ```/path/to/libSlimGuard``` 17 | 18 | To use SlimGuard, you can 19 | 1. link __libSlimGuard__ to your executable 20 | 21 | 2. setting ```LD_PRELOAD``` as an enviromment variable using 22 | ```bash 23 | export LD_PRELOAD=/path/to/libSlimGuard.so 24 | ``` 25 | 26 | 3. simply run as 27 | ``` 28 | LD_PRELOAD=/path/to/libSlimGuard.so /your/app 29 | ``` 30 | 31 | #### Tests 32 | 33 | For this use cmake: 34 | ``` 35 | mkdir build 36 | cd build 37 | cmake .. 38 | make 39 | make test 40 | ``` 41 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /doc/artifacts_available.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/artifacts_available.jpg -------------------------------------------------------------------------------- /doc/artifacts_evaluated_functional.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/artifacts_evaluated_functional.jpg -------------------------------------------------------------------------------- /doc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/logo.png -------------------------------------------------------------------------------- /doc/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/overview.png -------------------------------------------------------------------------------- /doc/pcg32-license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /doc/slides/Makefile: -------------------------------------------------------------------------------- 1 | TEXMF=/usr/share/texlive/texmf-dist 2 | PDFREADER=evince 3 | 4 | THEME=beamerthemessrg.sty 5 | INNER=beamerinnerthemessrg.sty 6 | COLOR=beamercolorthemessrg.sty 7 | TITLE_FRAME_BG=include/ssrg-title-frame-bg.pdf 8 | NORMAL_FRAME_BG=include/ssrg-normal-frame-bg.pdf 9 | 10 | SAMPLE_DOC=slimguard 11 | 12 | all: compile_sample 13 | make clean 14 | install: 15 | cp -f $(THEME) $(TEXMF)/tex/latex/beamer/themes/theme/ 16 | cp -f $(COLOR) $(TEXMF)/tex/latex/beamer/themes/color/ 17 | cp -f $(INNER) $(TEXMF)/tex/latex/beamer/themes/inner/ 18 | mkdir -p $(TEXMF)/tex/generic/images 19 | cp -f $(TITLE_FRAME_BG) $(TEXMF)/tex/generic/images/ 20 | cp -f $(NORMAL_FRAME_BG) $(TEXMF)/tex/generic/images/ 21 | mktexlsr 22 | texhash 23 | 24 | compile_sample: 25 | pdflatex --draftmode $(SAMPLE_DOC) 26 | pdflatex $(SAMPLE_DOC) 27 | 28 | show: compile_sample 29 | $(PDFREADER) $(SAMPLE_DOC).pdf 30 | 31 | clean: 32 | rm -rf *.log *.aux *.out *.bbl *.blg *.nav *.snm *.toc *.vrb 33 | 34 | superclean: clean 35 | rm -rf $(SAMPLE_DOC).pdf 36 | -------------------------------------------------------------------------------- /doc/slides/Presentation.md: -------------------------------------------------------------------------------- 1 | ### Intro 2 | Hello everyone, thanks for coming to my defense. My Thesis topic is "Design and 3 | Implementation of a memory efficient and secure heap allocator. 4 | 5 | ### Motivation 6 | In the past decade, "heap" have become a more and more popular word in the 7 | vulnerability database. In this figure, it showed the number of heap-related 8 | vulnerability entries since 2010. As you can see, the number has increased a 9 | lot since 2016. 10 | 11 | What are these vulnerabilities? 12 | These includes buffer overflows/overreads, use-after-free, double/invalid 13 | frees. 14 | 15 | ### Heap Vulnerabilities 16 | A buffer overflow frequently happened in memory unsafe languages such as C/C++. 17 | For example, assume the user is trying to allocate 8 byte of memory, and 18 | somehow, there isn't any boundary check for this allocation. So the user can 19 | write 10 bytes to the buffer. This allocation overflowed two bytes, which may 20 | potentally overwrite the next buffer. 21 | 22 | Use-after-free is the application is trying to use a free'd buffer. 23 | 24 | Double free is the application is trying to free a free'd buffer again. 25 | 26 | heap vulnerabilities can lead to serious problems such as data/metadata 27 | corruption, control flow hijacking, information leaks, etc. 28 | 29 | ### Related works 30 | 31 | One solution to solve these heap related vulnerabilties is to use a secure heap 32 | allocator also known as a secure malloc algorithm 33 | 34 | OpenBSD allocators provide some heap protections such as segratagation of 35 | metadata, randomized allocation, it is not very secure 36 | 37 | Early works such as DieHarder provided some new techniques such as 38 | over-provisioning. but it is slow, which means the performance overhead is 39 | huge. 40 | 41 | Recent works FreeGuard and Guarder provide high performanace, secure memory 42 | allocator. however its memory overhead is more than 2x in a lot of sceriano 43 | 44 | But they all suffer one big problem: Memory overhead. Existing secure allocator 45 | are either not secure or memory efficient. 46 | 47 | ### proposal 48 | 49 | Here we propose slimguard! A secure memory allocator, not only has negligible 50 | performance overhead and competetive security guarantees, but alsoo more 51 | importantly it is memory efficient. 52 | 53 | ### Design 54 | 55 | First of, let me talk about general non-secure designs. 56 | 57 | #### Freelist 58 | There are two different types of memory allocators. The first one is free-list 59 | based allocator. GlibC's default allocator is free-list based allocator. It rounds 60 | the size of the object to 8 or 16 bytes depending on the architecture. and it 61 | stores the size right before the heap object. 62 | 63 | For instance, in this figure, if the application is trying to allocate a 64 | buffer, it will give the return addr, shown here. After this ret addr, it is 65 | the buffer space, before the return addr, it is the metadata. 66 | 67 | As you can see the free-list based allocator is not very secure, because it 68 | is desgined for performance and stability. 69 | 70 | #### Bibop 71 | Another type of heap allocator is Bibop style. BIBOP means Big Bag of Pages. 72 | OpenBSD Guarder and other secure memory allcoators are designed this way. 73 | It has a power-of-2 class size, meaning each bag has the same slot that is 74 | power-of-2. For example, if the user is trying to allocate 4098 bytes, it will 75 | come here. But what if you want to allocate 2048+1 bytes? Since there is only 76 | 2048 and 4096 size classes, so the allocator has to sacrifice 2047 bytes and 77 | give it a 4096 byte slot. This s a huge waste of memory. 78 | 79 | #### Slimguard 80 | On the other hand, slimguard is designed with fine-grainede size classes. it 81 | has subdivisions between the power-of-2 size classes. For example, if the user 82 | is allocating 129 bytes. Instead of going to 256 byte slots, it will go to the 83 | size-class with an index of 17. This fine-grained classes can save a lot of 84 | memoreis at runtime. 85 | 86 | 87 | #### Malloc path 88 | 89 | When we have a malloc, we will use the size x to calculate the size class index 90 | I. In the class size index I, we will randomly find a slot in the free-listi, 91 | write the corresponding metadata and return the the address to the user. 92 | 93 | #### free path 94 | 95 | When we free an object, slimguard will find the class size index I, and write 96 | the corresponding metadata. 97 | 98 | #### Multi-threading support 99 | Slimguard is using a fine-grained mutex lock to secure the critical sections, 100 | the buffer and the metadata. So a lot of computations can be done in parallel. 101 | 102 | #### Binary Compatibailty 103 | Slimguard supports all of the memory allocation APIs includes malloc, free, 104 | realloc, memalign, and it is designed as a dynamic library, so it can be easily 105 | linked to an existing bianry. 106 | 107 | ### Security features 108 | Next, lets talk about the security features in SlimGuard. 109 | 110 | #### Randomization Allocatoin 111 | 112 | In order to make it harder for the attacker to guess what is the next return address 113 | we have to make it as random as possible. In order to achieve this goal, we build a 114 | very large array, it contains a lot of poitners(2^10) that can be used to serve a 115 | memory allocation. Everytime a pointer is randomly chosen, slimguard will fill 116 | the next possible slot to this free array in order to make sure it always have 117 | enough free slot to use. 118 | 119 | #### Metadata segrafation 120 | 121 | To prevent the metadata to be overwritten, Slimguard separated the metadata and 122 | the objects itself. As you can see, Part B and Part C are separated in two 123 | non-contingenious memory area. This will make sure that the metadata cannot be 124 | overwritten. 125 | 126 | #### Dynamic Canary 127 | 128 | In order to detect the buffer overflows, SlimGuard introduced a new technique: 129 | Dynamic Canary. This is a hased value based on the return address of each buffer. 130 | Since the return address differs from on and the other, so techniqually, each 131 | slot will have a different value of canary. In this way, SlimGuard does not 132 | have to store the canary value, which makes it more secure comparing to the others. 133 | Results also shown the overhead comes from this part is negligible. 134 | 135 | #### Guard Oages 136 | 137 | Guard pages is another way to detch buffer overflows. It can immediately detect buffer 138 | overflow since each guard page here is unmapped pages. If an overwrite writes the 139 | guard page, a seg fault will immmediately detect the overflow. Since the cost of 140 | deploying guard pages are huge. So we make it fully on demand. i.e. we do not 141 | pre-set guard pages. This will shorten the initialization time for the allocator. 142 | 143 | #### Other security features 144 | 145 | destroy onfree 146 | 147 | delayed memory reuse 148 | 149 | ### results 150 | top: memory overhead 151 | 152 | bottom performance 153 | 154 | x axis, y axis, different colors 155 | 156 | multi-threading up to 64 threads 157 | 158 | security features 159 | Lastly, let's see how slimguard detects real-world bugs: 160 | 1. gzip and ncompress contains buffer overflow due to strcpy 161 | without proper boundary checks. SlimGuards can detect them 162 | when it checks the canray value, so it reports the overflow and 163 | halt the program. 164 | 165 | 2. ed and ImageMagic contains double or invalid frees, which can be 166 | immeditately detected by slimguard when it happens. 167 | 168 | ### Conclusion 169 | 170 | -------------------------------------------------------------------------------- /doc/slides/include/CVE.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/CVE.pdf -------------------------------------------------------------------------------- /doc/slides/include/Readme.md: -------------------------------------------------------------------------------- 1 | It is generally better to include pictures (graphs and schemas) as PDF in latex 2 | because they are vector graphics so they render really well in the paper PDF. 3 | To get rid of whatever margin a picture in PDF has (we don't want any when 4 | including the picture in the paper), use pdfcrop: 5 | ``` 6 | pdfcrop pic.pdf pic.pdf 7 | ``` 8 | 9 | -------------------------------------------------------------------------------- /doc/slides/include/TLSF.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/TLSF.pdf -------------------------------------------------------------------------------- /doc/slides/include/artifacts_available.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/artifacts_available.jpg -------------------------------------------------------------------------------- /doc/slides/include/artifacts_evaluated_functional.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/artifacts_evaluated_functional.jpg -------------------------------------------------------------------------------- /doc/slides/include/artifacts_evaluated_reusable.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/artifacts_evaluated_reusable.jpg -------------------------------------------------------------------------------- /doc/slides/include/bibop_heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/bibop_heap.png -------------------------------------------------------------------------------- /doc/slides/include/buffer_overflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/buffer_overflow.png -------------------------------------------------------------------------------- /doc/slides/include/design-space.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/design-space.pdf -------------------------------------------------------------------------------- /doc/slides/include/entropy-mem.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/entropy-mem.pdf -------------------------------------------------------------------------------- /doc/slides/include/entropy-time.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/entropy-time.pdf -------------------------------------------------------------------------------- /doc/slides/include/gp-ratio.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/gp-ratio.pdf -------------------------------------------------------------------------------- /doc/slides/include/init.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/init.pdf -------------------------------------------------------------------------------- /doc/slides/include/inline_metadata.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/inline_metadata.png -------------------------------------------------------------------------------- /doc/slides/include/macro-mem.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/macro-mem.pdf -------------------------------------------------------------------------------- /doc/slides/include/macro-time.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/macro-time.pdf -------------------------------------------------------------------------------- /doc/slides/include/multithreading.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/multithreading.pdf -------------------------------------------------------------------------------- /doc/slides/include/overview.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/overview.odg -------------------------------------------------------------------------------- /doc/slides/include/overview.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/overview.pdf -------------------------------------------------------------------------------- /doc/slides/include/overview1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/overview1.pdf -------------------------------------------------------------------------------- /doc/slides/include/overview2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/overview2.pdf -------------------------------------------------------------------------------- /doc/slides/include/overview3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/overview3.pdf -------------------------------------------------------------------------------- /doc/slides/include/table-features.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/table-features.odt -------------------------------------------------------------------------------- /doc/slides/include/table-features.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/include/table-features.pdf -------------------------------------------------------------------------------- /doc/slides/slimguard.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ssrg-vt/SlimGuard/6d7d065ac9ce7203250aa44b4b333b58ca93c803/doc/slides/slimguard.pdf -------------------------------------------------------------------------------- /doc/slides/slimguard.tex: -------------------------------------------------------------------------------- 1 | \documentclass{beamer} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[T1]{fontenc} 4 | \setbeamertemplate{caption}[numbered] 5 | 6 | % \title{\textbf{SlimGuard: A Secure and Memory-Efficient Heap Allocator}} 7 | \title{\textbf{SlimGuard: A Secure and Memory Efficient Heap Allocator}} 8 | \date{12/11/2019} 9 | \author{\underline{Beichen Liu}, Pierre Olivier, Binoy Ravindran\\ 10 | \small ECE, Virginia Tech} 11 | 12 | \graphicspath{{./include/}} 13 | 14 | \usetheme{ssrg} 15 | 16 | \begin{document} 17 | 18 | %% Page 1 19 | \begin{frame} 20 | \titlepage 21 | \end{frame} 22 | 23 | %% Page 2 24 | \section{Background and Motivation} 25 | \subsection{Motivation} 26 | \begin{frame} 27 | \frametitle{\secname} 28 | \framesubtitle{\subsecname} 29 | \begin{figure} 30 | \centering 31 | \includegraphics{CVE.pdf} 32 | \\Number of heap-related CVE entries since 2010. 33 | 34 | \end{figure} 35 | \end{frame} 36 | 37 | 38 | % Page 3 39 | \section{Background and Motivation} 40 | \subsection{Heap Vulnerabilities} 41 | \begin{frame} 42 | \frametitle{\secname} 43 | \framesubtitle{\subsecname} 44 | \begin{itemize} 45 | \item buffer overflow, buffer overread 46 | \begin{figure} 47 | \centering 48 | \includegraphics[scale=0.3]{buffer_overflow} 49 | \\Buffer overflow example 50 | \end{figure} 51 | \item use-after-free/double free 52 | \item invalid free 53 | \end{itemize} 54 | \end{frame} 55 | 56 | % Page 4 57 | \section{Background and Motivation} 58 | \subsection{Related Works} 59 | \begin{frame} 60 | \frametitle{\secname} 61 | \framesubtitle{\subsecname} 62 | 63 | One solution for these heap vulnerabilities is to use a secure heap 64 | allocator, aka use a secure malloc algorithm.\\ 65 | \begin{itemize} 66 | \item OpenBSD 67 | \begin{itemize} 68 | \item segragation of metadata 69 | \item randomized allocation 70 | \item security guarantees are not competitive 71 | \end{itemize} 72 | \item DieHarder(PLDI'06) 73 | \begin{itemize} 74 | \item randomized allocation 75 | \item over-provisioning 76 | \item memory overhead is large 77 | \end{itemize} 78 | \item FreeGuard(CCS'17) and Guarder(USENIX'18) 79 | \begin{itemize} 80 | \item high performance 81 | \item high security guarantee 82 | \item memory overhead is large 83 | \end{itemize} 84 | \end{itemize} 85 | \end{frame} 86 | 87 | % Page 5 88 | \section{Background and Motivation} 89 | \subsection{Related Works} 90 | \begin{frame} 91 | \frametitle{\secname} 92 | \framesubtitle{\subsecname} 93 | 94 | Existing secure allocator are either not really secure or \textbf{not memory 95 | efficient}. 96 | 97 | \end{frame} 98 | 99 | % Page 6 100 | \section{Design and Implementation} 101 | \begin{frame} 102 | \frametitle{\secname} 103 | \begin{figure} 104 | \centering 105 | \includegraphics[scale=0.6]{design-space.pdf} 106 | \\SlimGuard in the secure allocators design space. 107 | \vspace{-4pt} 108 | \end{figure} 109 | Design Objective: \textbf{memory efficiency}, competitive security guarantees, 110 | and negligible performance overhead. 111 | \end{frame} 112 | 113 | % Page 7 114 | \section{Design and Implementation} 115 | \subsection{General Design} 116 | \begin{frame} 117 | \frametitle{\secname} 118 | \framesubtitle{\subsecname} 119 | \begin{enumerate} 120 | \item size class management 121 | \item malloc path 122 | \item free path 123 | \item multithreading, binary compatibility 124 | \end{enumerate} 125 | \end{frame} 126 | 127 | % Page 8 128 | \section{Design and Implementation} 129 | \subsection{Size Classes Management} 130 | \begin{frame} 131 | \frametitle{\secname} 132 | \framesubtitle{\subsecname} 133 | free-list(e.g., ptmallocv2) 134 | \begin{itemize} 135 | \item round size up to a multiple of 8 or 16 bytes 136 | \item store the size right before the heap object 137 | \end{itemize} 138 | \begin{figure} 139 | \centering 140 | \includegraphics[scale=0.6]{inline_metadata} 141 | \\ Inline metadata example 142 | \end{figure} 143 | \end{frame} 144 | 145 | % Page 9 146 | \section{Design and Implementation} 147 | \subsection{Size Classes Management} 148 | \begin{frame} 149 | \frametitle{\secname} 150 | \framesubtitle{\subsecname} 151 | bibop style (e.g., OpenBSD, Guarder) 152 | \begin{itemize} 153 | \item power-of-2 class size 154 | \item a memory region are equally divided into classs size 155 | \end{itemize} 156 | \begin{figure} 157 | \centering 158 | \includegraphics[scale=0.6]{bibop_heap} 159 | \\ BIBOP heap example 160 | \end{figure} 161 | \end{frame} 162 | 163 | % Page 10 164 | \section{Design and Implementation} 165 | \subsection{SlimGuard Size Classed Management} 166 | \begin{frame} 167 | \frametitle{\secname} 168 | \framesubtitle{\subsecname} 169 | SlimGuard: Fine-grained size class management 170 | \begin{figure} 171 | \centering 172 | \includegraphics[scale=0.4]{overview1.pdf} 173 | \\ SlimGuard Design Space 174 | \end{figure} 175 | \end{frame} 176 | 177 | % Page 11 178 | \section{Design and Implementation} 179 | \subsection{SlimGuard Malloc Path} 180 | \begin{frame}[fragile] 181 | \frametitle{\secname} 182 | \framesubtitle{\subsecname} 183 | \begin{verbatim} 184 | void *pointer = malloc(x); 185 | \end{verbatim} 186 | \begin{figure} 187 | \centering 188 | \includegraphics[scale=0.4]{overview1.pdf} 189 | \\ SlimGuard Design Space 190 | \end{figure} 191 | \end{frame} 192 | 193 | % Page 12 194 | \section{Design and Implementation} 195 | \subsection{SlimGuard Malloc Path} 196 | \begin{frame}[fragile] 197 | \frametitle{\secname} 198 | \framesubtitle{\subsecname} 199 | \begin{verbatim} 200 | void *pointer = malloc(x); 201 | \end{verbatim} 202 | \begin{figure} 203 | \centering 204 | \includegraphics[scale=0.35]{overview2.pdf} 205 | \\ SlimGuard Design Space 206 | \end{figure} 207 | \end{frame} 208 | 209 | % Page 13 210 | \section{Design and Implementation} 211 | \subsection{SlimGuard Free Path} 212 | \begin{frame}[fragile] 213 | \frametitle{\secname} 214 | \framesubtitle{\subsecname} 215 | \begin{verbatim} 216 | free(pointer); 217 | \end{verbatim} 218 | \begin{figure} 219 | \centering 220 | \includegraphics[scale=0.35]{overview3.pdf} 221 | \\ SlimGuard Design Space 222 | \end{figure} 223 | \end{frame} 224 | 225 | % Page 14 226 | \section{Design and Implementation} 227 | \subsection{Other Features} 228 | \begin{frame} 229 | \frametitle{\secname} 230 | \framesubtitle{\subsecname} 231 | \begin{itemize} 232 | \item \textbf{Multithreading Support}\\ 233 | thread-safe with fine-grained locks 234 | \item \textbf{Binary Compatibility}\\ 235 | A binary Compatible dynamic library \\ 236 | support malloc(), free(), realloc(), memalign() 237 | \end{itemize} 238 | \end{frame} 239 | 240 | % Page 15 241 | \section{Design and Implementation} 242 | \subsection{Security Features} 243 | \begin{frame} 244 | \frametitle{\secname} 245 | \framesubtitle{\subsecname} 246 | \begin{itemize} 247 | \item randomization allocation 248 | \item metadata segradation 249 | \item dynamic canary 250 | \item guard page 251 | \item destroy-on-free, delayed memory reuse, etc. 252 | \end{itemize} 253 | \end{frame} 254 | 255 | % Page 16 256 | \section{Design and Implementation} 257 | \subsection{Randomization Allocation} 258 | \begin{frame} 259 | \frametitle{\secname} 260 | \framesubtitle{\subsecname} 261 | \textbf{Goal}: make it harder to guess where the next object is located \\ 262 | \textbf{Solution}: Build a large enough free array(G in figure) 263 | \begin{figure} 264 | \centering 265 | \includegraphics[scale=0.35]{overview3.pdf} 266 | \\ SlimGuard Design Space 267 | \end{figure} 268 | \end{frame} 269 | 270 | % Page 17 271 | \section{Design and Implementation} 272 | \subsection{Metadata Segregation} 273 | \begin{frame} 274 | \frametitle{\secname} 275 | \framesubtitle{\subsecname} 276 | \textbf{Goal}: prevent metadata to be overwritten \\ 277 | \textbf{Solution}: A separate region for metadata(A and B in figure) 278 | \begin{figure} 279 | \centering 280 | \includegraphics[scale=0.35]{overview3.pdf} 281 | \\ SlimGuard Design Space 282 | \end{figure} 283 | \end{frame} 284 | 285 | % Page 18 286 | \section{Design and Implementation} 287 | \subsection{Dynamic Canary} 288 | \begin{frame} 289 | \frametitle{\secname} 290 | \framesubtitle{\subsecname} 291 | \textbf{Goal}: Detect buffer overflow \\ 292 | \textbf{Solution}: A hashed value based on return address(red block in data area) 293 | \begin{figure} 294 | \centering 295 | \includegraphics[scale=0.35]{overview3.pdf} 296 | \\ SlimGuard Design Space 297 | \end{figure} 298 | \end{frame} 299 | 300 | % Page 19 301 | \section{Design and Implementation} 302 | \subsection{Guard Pages} 303 | \begin{frame} 304 | \frametitle{\secname} 305 | \framesubtitle{\subsecname} 306 | \textbf{Goal}: Detect buffer overflow immediately \\ 307 | \textbf{Solution}: fully on demand guard pages(J in figure) 308 | \begin{figure} 309 | \centering 310 | \includegraphics[scale=0.35]{overview3.pdf} 311 | \\ SlimGuard Design Space 312 | \end{figure} 313 | \end{frame} 314 | 315 | 316 | % Page 20 317 | \section{Design and Implementation} 318 | \subsection{Other Security Features} 319 | \begin{frame} 320 | \frametitle{\secname} 321 | \framesubtitle{\subsecname} 322 | \begin{itemize} 323 | \item Destroy-on-Free\\ 324 | zero out the free area 325 | \item delayed memory reuse\\ 326 | a side-effect from our randomization 327 | \end{itemize} 328 | \end{frame} 329 | 330 | % Page 21 331 | \section{Results} 332 | \subsection{Performance and Memory Overhead Analysis} 333 | \begin{frame} 334 | \frametitle{\secname} 335 | \framesubtitle{\subsecname} 336 | \begin{figure} 337 | \centering 338 | \includegraphics[scale=0.3]{macro-mem.pdf} 339 | \\ 340 | \includegraphics[scale=0.3]{macro-time.pdf} 341 | \\Memory footprint (top) and execution time (bottom) of SlimGuard, 342 | OpenBSD and Guarder for PARSEC (\texttt{p-*}) and MiBench (\texttt{m-*}) 343 | macro-benchmarks. All values are normalized to Glibc's memory footprint 344 | and execution time. 345 | \end{figure} 346 | \end{frame} 347 | 348 | % Page 22 349 | \section{Results} 350 | \subsection{Multitheading} 351 | \begin{frame} 352 | \frametitle{\secname} 353 | \framesubtitle{\subsecname} 354 | \begin{figure} 355 | \centering 356 | \includegraphics[scale=0.6]{multithreading.pdf} 357 | \\Multithreading memory overhead (top) and performance (bottom) 358 | results. 359 | 360 | \end{figure} 361 | \end{frame} 362 | 363 | % Page 23 364 | \section{Results} 365 | \subsection{Security Analysis} 366 | \begin{frame} 367 | \frametitle{\secname} 368 | \framesubtitle{\subsecname} 369 | SlimGuard's efficiency on real-world bugs 370 | \begin{columns} 371 | \begin{column}{0.5\textwidth} 372 | \begin{itemize} 373 | \item gzip-1.2.4 374 | \item ncompress-4.2.4 375 | \item ed-1.14.1 376 | \item ImageMagic 7.0.4-1 377 | \end{itemize} 378 | \end{column} 379 | 380 | \begin{column}{0.5\textwidth} 381 | \textbf{SlimGuard successfully detects the exploit in all cases.} 382 | 383 | \end{column} 384 | \end{columns} 385 | 386 | \end{frame} 387 | 388 | 389 | % Page 24 390 | \section{Conclusion} 391 | \begin{frame} 392 | \frametitle{\secname} 393 | 394 | \begin{itemize} 395 | \item Memory overhead is not acceptable in the state-of-the-art memory allocator 396 | \item Slimguard: memory-efficient and secure allocator 397 | \item Memory overhead is much smaller than state-of-the-art allocator 398 | \end{itemize} 399 | \end{frame} 400 | 401 | % Page 25 402 | \section{SlimGuard's Source Code} 403 | \begin{frame} 404 | 405 | \frametitle{\secname} 406 | SlimGuard\footnotemark is an open-source project of the Systems Software Research Group 407 | at Virginia Tech. 408 | \\ 409 | Source Available at \textbf{https://ssrg-vt.github.io/SlimGuard/} 410 | \\ 411 | Docker with benchmarks available at \\ 412 | \textbf{https://hub.docker.com/repository/docker/bcliu430/slimguard} 413 | 414 | \footnotetext{SlimGuard is supported in part by ONR under grants N00014-16-1-2104 and 415 | N00014-18-1-2022. 416 | \\ 417 | } 418 | \end{frame} 419 | 420 | \end{document} 421 | -------------------------------------------------------------------------------- /include/debug.h: -------------------------------------------------------------------------------- 1 | /* debug.h 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #ifndef DEBUG_H 8 | #define DEBUG_H 9 | 10 | #define RED "\x1b[31m" 11 | #define YELLOW "\x1b[33m" 12 | #define GREEN "\x1b[32m" 13 | #define END "\x1b[0m" 14 | 15 | #ifdef DEBUG 16 | #define Debug(fmt, ...) \ 17 | do { \ 18 | fprintf(stderr, YELLOW "[ln %d] in %s " fmt END, \ 19 | __LINE__, __func__, __VA_ARGS__); \ 20 | } while(0) 21 | #else 22 | #define Debug(...) 23 | #endif 24 | 25 | #ifdef DEBUG 26 | #define Canary(fmt, ...) \ 27 | do { \ 28 | fprintf(stderr, GREEN "%s " fmt END, __func__, __VA_ARGS__); \ 29 | } while(0) /* canary related print */ 30 | #else 31 | #define Canary( ...) 32 | #endif 33 | 34 | #define Error(fmt, ...) \ 35 | do{ \ 36 | fprintf(stderr, RED "ERROR: %s #%d " fmt END, \ 37 | __func__, __LINE__, __VA_ARGS__); \ 38 | } while(0) 39 | 40 | #define PRINT(fmt, ...) \ 41 | do { \ 42 | frpintf(stderr, "[%d:] %s ", \ 43 | __LINE__ , __func__, __VA_ARGS__); \ 44 | } while(0) 45 | 46 | #endif /* DEBUG_H */ 47 | -------------------------------------------------------------------------------- /include/slimguard-large.h: -------------------------------------------------------------------------------- 1 | /* slimguard-large.h 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #ifndef SG_LARGE_H 8 | #define SG_LARGE_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "debug.h" 18 | 19 | typedef struct large_obj_t { 20 | void* start_addr; 21 | uint32_t align_size; 22 | struct large_obj_t *next; 23 | } large_obj_t; 24 | 25 | large_obj_t *next_obj(large_obj_t *node); 26 | void add_large(void *addr, uint32_t align_sz); 27 | void remove_large(const void *target); 28 | large_obj_t *in_list(const void *target); 29 | size_t get_large_object_size(void *target); 30 | 31 | void print_large(); 32 | 33 | void *xxmalloc_large(size_t sz, uint32_t align); 34 | int xxfree_large(void *ptr); 35 | 36 | #endif /* SG_LARGE_H */ 37 | -------------------------------------------------------------------------------- /include/slimguard-mmap.h: -------------------------------------------------------------------------------- 1 | #ifndef SLIMGUARD_MMAP_H 2 | #define SLIMGUARD_MMAP_H 3 | 4 | #include 5 | 6 | void * slimguard_mmap(uint64_t size, uint64_t align); 7 | 8 | #endif /* SLIMGUARD_MMAP_H */ 9 | -------------------------------------------------------------------------------- /include/slimguard.h: -------------------------------------------------------------------------------- 1 | /* slimguard.h 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #ifndef SLIMGUARD_H 8 | #define SLIMGUARD_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define ETP (8) // entropy to 8 bits 19 | #define GP (10) // 1 guard page per GP pages 20 | #define BKT (1 << ETP) // bucket size 21 | #define ALIGN (7) // alignment 22 | #define MAX_EXP (17) // max size allocate 23 | #define MIN_EXP (6) // smallest blk 24 | #define FLI (MAX_EXP - MIN_EXP + 1) // num of first level index 25 | #define SLI_LOG2 (4) // number of second level index 26 | #define SLI (1<< SLI_LOG2) 27 | #define SMALL_BLK (1 << (MIN_EXP+1)) 28 | #define ELE (1<<24) // 3 ** 24 elements 29 | #define SEED_MAX (1 << 10) 30 | #define PAGE_SIZE (1 << 12) 31 | #define INDEX (FLI*SLI) 32 | #define BUCKET_SIZE (8UL << 30) // 8GB 33 | 34 | #if INDEX >= 255 35 | #error "INDEX should be < 255 as it is stored on 1 unsigned byte" 36 | #endif 37 | 38 | int log2_64(uint64_t value); 39 | uint8_t sz2cls(uint32_t sz); 40 | uint32_t cls2sz(uint16_t cls); 41 | uint64_t round_size(uint64_t sz); 42 | 43 | void* get_mem(uint64_t size, uint32_t align); 44 | void init_bibop(); 45 | void init_bucket(uint8_t index); 46 | void* get_next(uint8_t index); 47 | void* get_random_obj(uint8_t index); 48 | 49 | char HashPointer(const void *ptr); 50 | void set_canary(void *ptr, uint8_t index); 51 | void get_canary(const void *ptr, const uint8_t index); 52 | 53 | void mark_used(void *ptr, uint8_t index); 54 | void mark_free(void *ptr, uint8_t index); 55 | 56 | #ifdef RELEASE_MEM 57 | void increment_pc(void *ptr, uint8_t index); 58 | void decrement_pc(void *ptr, uint8_t index); 59 | #endif 60 | 61 | void * xxmalloc(size_t sz); 62 | void xxfree(void *ptr); 63 | void * xxrealloc(void *ptr, size_t size); 64 | void * xxmemalign(size_t alignment, size_t size); 65 | void * xxcalloc(size_t nmemb, size_t size); 66 | 67 | void* slimguard_malloc(size_t sz); 68 | void slimguard_free(void *ptr); 69 | void* slimguard_realloc(void *ptr, size_t sz); 70 | void* slimguard_memalign(size_t alignment, size_t sz); 71 | 72 | #endif /* SLIMGUARD_H */ 73 | -------------------------------------------------------------------------------- /include/sll.h: -------------------------------------------------------------------------------- 1 | /* sll.h 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #ifndef SLL_H 8 | #define SLL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include "debug.h" 14 | 15 | typedef struct sll_t { 16 | struct sll_t *next; 17 | } sll_t; 18 | 19 | sll_t* add_head(sll_t* node, sll_t* slist); 20 | sll_t* remove_head(sll_t* slist); 21 | 22 | #endif /* SLL_H */ 23 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | * * * 2 | 3 |

4 | 5 |

6 | 7 | **News** 8 | 9 | - Check out this [paper](https://drive.google.com/file/d/1_kY88JfdVB7B-9Uh8kR37_pPgm0nXu8D/view?usp=drive_link) 10 | building on top of SlimGuard and enhancing it with fine grained hardware write-protection features (Intel SPP) 11 | - Our SlimGuard [paper](https://www.ssrg.ece.vt.edu/papers/middleware19-slimguard.pdf) has been accepted 12 | at [Middleware 2019](http://2019.middleware-conference.org/). 13 | 14 | * * * 15 | 16 | **Awards** 17 | 18 | SlimGuard is awarded the _artifacts available_ and _artifacts evaluated_ functional badges. 19 | 20 | 21 | 22 | 23 | 24 | * * * 25 | 26 | You can download SlimGuard on 27 | [Github](https://github.com/ssrg-vt/SlimGuard/). 28 | 29 | SlimGuard is a secure dynamic memory allocator whose design is driven by memory 30 | efficiency. We redesign the security features of state-of-the-art allocators 31 | with memory efficiency in mind. SlimGuard protects against widespread 32 | heap-related attacks such as overflows, over-reads, double/invalid free, and 33 | use-after-free. Among other features, SlimGuard uses an efficient fine-grain 34 | size classes indexing mechanism and implements a novel dynamic canary scheme 35 | optimized for memory overhead reduction. 36 | 37 | ![](https://raw.githubusercontent.com/ssrg-vt/SlimGuard/master/doc/overview.png) 38 | 39 | ### Design Principles 40 | 41 | The security principles implemented within SlimGuard are the following: 42 | Randomized memory allocations with a significant entropy remove the capacity 43 | by the attacker to create a deterministic layout of objects on the heap. 44 | Over-provisioning protects in a probabilistic way against buffer overflows. 45 | Segregating metadata from data allows to pro- tect against metadata 46 | corruption-based attacks that are straightforward in systems storing 47 | metadata inline as headers with dynamically allocated objects. These metadata 48 | include in particular the state of each slot (free or used), checked upon free 49 | to protect against double-free-based attacks. Heap over- and under-flows are 50 | protected against with the use of heap canaries. Unmapped guard pages prevent 51 | heap buffer overflows and over-reads. Use-after-free attacks are made harder by 52 | using delayed randomized memory reuse and optionally destroying data on free. 53 | 54 | ### Contact 55 | 56 | [Beichen Liu](), Virginia Tech: beichen.liu *at* vt *dot* edu 57 | 58 | [Pierre Olivier](https://sites.google.com/view/pierreolivier), The University of Manchester: pierre.olivier *at* manchester.ac.uk 59 | 60 | * * * 61 | 62 | SlimGuard is an open-source project of the [Systems Software Research 63 | Group](https://www.ssrg.ece.vt.edu/) at [Virginia Tech](https://vt.edu/). 64 | 65 | SlimGuard is supported in part by ONR under grants N00014-16-1-2104 and 66 | N00014-18-1-2022. Any opinions, findings, and conclusions or recommendations 67 | expressed in this site are those of the author(s) and do not necessarily 68 | reflect the views of ONR. 69 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7.2) # CMake version check 2 | project(SlimGuard) 3 | 4 | set(debug off) 5 | set(canary on) 6 | set(release-memory on) 7 | set(guardpage on) 8 | set(destroy-on-free off) 9 | 10 | include_directories(../include/) 11 | 12 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-deprecated-declarations -O2") 13 | 14 | if(debug) 15 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -DDEBUG") 16 | endif(debug) 17 | 18 | if(canary) 19 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_CANARY") 20 | endif(canary) 21 | 22 | if(release-memory) 23 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DRELEASE_MEM") 24 | endif(release-memory) 25 | 26 | if(guardpage) 27 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGUARDPAGE") 28 | endif(guardpage) 29 | 30 | if(destroy-on-free) 31 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDESTROY_ON_FREE") 32 | endif(destroy-on-free) 33 | 34 | set(SlimGuard-src 35 | ../include/debug.h 36 | ../include/slimguard.h slimguard.c 37 | ../include/slimguard-large.h slimguard-large.c 38 | ../include/slimguard-mmap.h slimguard-mmap.c 39 | ../include/sll.h sll.c 40 | gnuwrapper.cpp) 41 | 42 | add_library(SlimGuard SHARED ${SlimGuard-src}) 43 | -------------------------------------------------------------------------------- /src/gnuwrapper.cpp: -------------------------------------------------------------------------------- 1 | /* gnuwrapper.cpp 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #ifdef __linux__ 8 | 9 | #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 34 10 | 11 | #ifndef __GNUC__ 12 | #error "This file requires the GNU compiler." 13 | #endif 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | #ifndef CUSTOM_PREFIX 22 | #define CUSTOM_PREFIX(x) slimguard_##x 23 | #endif 24 | 25 | #define CUSTOM_MALLOC(x) CUSTOM_PREFIX(malloc)(x) 26 | #define CUSTOM_FREE(x) CUSTOM_PREFIX(free)(x) 27 | #define CUSTOM_REALLOC(x,y) CUSTOM_PREFIX(realloc)(x,y) 28 | #define CUSTOM_MEMALIGN(x,y) CUSTOM_PREFIX(memalign)(x,y) 29 | 30 | 31 | extern "C" { 32 | 33 | void * CUSTOM_MALLOC(size_t); 34 | void CUSTOM_FREE(void *); 35 | void * CUSTOM_REALLOC(void *, size_t); 36 | void * CUSTOM_MEMALIGN(size_t, size_t); 37 | 38 | static void my_init_hook (void); 39 | 40 | // New hooks for allocation functions. 41 | static void * my_malloc_hook (size_t, const void *); 42 | static void my_free_hook (void *, const void *); 43 | static void * my_realloc_hook (void *, size_t, const void *); 44 | static void * my_memalign_hook (size_t, size_t, const void *); 45 | 46 | // Store the old hooks just in case. 47 | static void * (*old_malloc_hook) (size_t, const void *); 48 | static void (*old_free_hook) (void *, const void *); 49 | static void *(*old_realloc_hook)(void *ptr, size_t size, const void *caller); 50 | static void *(*old_memalign_hook)(size_t alignment, size_t size, 51 | const void *caller); 52 | 53 | void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) (void) = my_init_hook; 54 | 55 | static void my_init_hook (void) { 56 | // Store the old hooks. 57 | old_malloc_hook = __malloc_hook; 58 | old_free_hook = __free_hook; 59 | old_realloc_hook = __realloc_hook; 60 | old_memalign_hook = __memalign_hook; 61 | 62 | // Point the hooks to the replacement functions. 63 | __malloc_hook = my_malloc_hook; 64 | __free_hook = my_free_hook; 65 | __realloc_hook = my_realloc_hook; 66 | __memalign_hook = my_memalign_hook; 67 | 68 | } 69 | 70 | static void * my_malloc_hook (size_t size, const void *) { 71 | void * result = CUSTOM_MALLOC(size); 72 | return result; 73 | } 74 | 75 | static void my_free_hook (void * ptr, const void *) { 76 | CUSTOM_FREE(ptr); 77 | } 78 | 79 | static void * my_realloc_hook (void * ptr, size_t size, const void *) { 80 | return CUSTOM_REALLOC(ptr, size); 81 | } 82 | 83 | static void * my_memalign_hook (size_t size, size_t alignment, const void *) { 84 | return CUSTOM_MEMALIGN(size, alignment); 85 | } 86 | 87 | #if 0 88 | void finalizer (void) __attribute__((destructor)); 89 | 90 | void finalizer (void) { 91 | printf ("counter = %d\n", counter); 92 | } 93 | #endif 94 | 95 | } 96 | 97 | #endif /* __GLIBC__ == 2 && __GLIBC_MINOR__ < 34 */ 98 | 99 | #endif /* __linux__ */ 100 | -------------------------------------------------------------------------------- /src/slimguard-large.c: -------------------------------------------------------------------------------- 1 | /* slimguard-large.c 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #include "debug.h" 8 | #include "slimguard-large.h" 9 | #include "slimguard-mmap.h" 10 | 11 | #define N (1<<10) // number of large object 12 | 13 | pthread_mutex_t lock; 14 | large_obj_t* large_list = NULL; 15 | 16 | large_obj_t* next_obj(large_obj_t *node) { 17 | return node->next; 18 | } 19 | 20 | void add_large(void *addr, uint32_t align_sz) { 21 | if (large_list == NULL) { 22 | 23 | large_list = (struct large_obj_t *) 24 | slimguard_mmap(sizeof(struct large_obj_t *), 0); 25 | if (large_list == NULL) { 26 | Error("fails to mmap for size %lu\n", sizeof(struct large_list *)); 27 | exit(-1); 28 | } 29 | 30 | large_list->start_addr = addr; 31 | large_list->align_size = align_sz; 32 | large_list->next = NULL; 33 | 34 | return; 35 | } 36 | 37 | large_obj_t *node = (struct large_obj_t *) 38 | slimguard_mmap(sizeof(struct large_obj_t *), 0); 39 | if (node == NULL) { 40 | Error("fails to mmap for size %lu\n", sizeof(struct large_obj_t *)); 41 | exit(-1); 42 | } 43 | 44 | node->start_addr = addr; 45 | node->align_size = align_sz; 46 | node->next = large_list; 47 | 48 | large_list = node; 49 | } 50 | 51 | void remove_large(const void *target) { 52 | large_obj_t *tmp = large_list, *pre; 53 | 54 | if ((tmp->next == NULL) | (tmp == NULL)) 55 | large_list = NULL; 56 | 57 | if ((tmp != NULL) && (tmp->start_addr == target)) { 58 | large_list = tmp->next; 59 | return; 60 | } 61 | 62 | while ((tmp != NULL) && (tmp->start_addr !=target)) { 63 | pre = tmp; 64 | tmp = tmp->next; 65 | } 66 | 67 | if (tmp == NULL) 68 | return; 69 | 70 | pre->next = tmp->next; 71 | } 72 | 73 | size_t get_large_object_size(void *target) { 74 | size_t ret = 0; 75 | large_obj_t * o = in_list(target); 76 | 77 | if(o) 78 | ret = o->align_size; 79 | 80 | return ret; 81 | } 82 | 83 | large_obj_t* in_list(const void *target) { 84 | if (large_list == NULL) 85 | return NULL; 86 | 87 | large_obj_t *curr = large_list; 88 | 89 | while (curr != NULL) { 90 | if (curr->start_addr == target) 91 | return curr; 92 | 93 | curr = next_obj(curr); 94 | } 95 | 96 | return NULL; 97 | } 98 | 99 | void print_large() { 100 | large_obj_t *tmp = large_list; 101 | 102 | while (tmp) { 103 | fprintf(stderr, "start %p\n", tmp->start_addr); 104 | tmp = tmp->next; 105 | } 106 | } 107 | 108 | void* xxmalloc_large(size_t sz, uint32_t align) { 109 | size_t need; 110 | void *ret; 111 | 112 | if (sz & 0xff) 113 | need = ((sz >> 8)+1) << 8; 114 | else 115 | need = sz; 116 | 117 | ret = slimguard_mmap(need, align); 118 | if (ret == NULL) { 119 | Error("fails to mmap for size %lu\n", sz); 120 | exit(-1); 121 | } 122 | 123 | /* Lock here */ 124 | pthread_mutex_lock(&lock); 125 | add_large(ret, need); 126 | pthread_mutex_unlock(&lock); 127 | /* Lock end */ 128 | 129 | return ret; 130 | } 131 | 132 | int xxfree_large(void *ptr) { 133 | large_obj_t *ret; 134 | ret = in_list(ptr); 135 | 136 | if(ret) { 137 | munmap(ptr, ret->align_size); 138 | 139 | /* Lock here */ 140 | pthread_mutex_lock(&lock); 141 | remove_large(ptr); 142 | pthread_mutex_unlock(&lock); 143 | /* Lock end */ 144 | 145 | return 1; 146 | 147 | } else { 148 | Error("Invalid address: %p\n", ptr); 149 | return -1; 150 | } 151 | 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /src/slimguard-mmap.c: -------------------------------------------------------------------------------- 1 | #include "slimguard-mmap.h" 2 | #include "slimguard.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void * slimguard_mmap(uint64_t size, uint64_t align) { 9 | 10 | if(align % PAGE_SIZE) { 11 | warnx("slimguard_mmap: bad alignment\n"); 12 | return NULL; 13 | } 14 | 15 | void *r = mmap(0, size + align, PROT_READ | PROT_WRITE, 16 | MAP_PRIVATE | MAP_ANON, -1, 0); 17 | 18 | if(r == MAP_FAILED) { 19 | warn("mmap(%lu)", size); 20 | return NULL; 21 | } 22 | 23 | if(align) { 24 | void *old_addr = r; 25 | r = (void *)(((uint64_t)r + align - 1) & ~(align - 1)); 26 | munmap(old_addr, (uint64_t)r - (uint64_t)old_addr); 27 | } 28 | 29 | return r; 30 | } 31 | -------------------------------------------------------------------------------- /src/slimguard.c: -------------------------------------------------------------------------------- 1 | /* slimguard.c 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #include "slimguard.h" 8 | #include "slimguard-large.h" 9 | #include "sll.h" 10 | #include "debug.h" 11 | #include "slimguard-mmap.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | typedef struct cls_t{ 18 | void* bucket[BKT]; // array for randomization and OP entropy 19 | void* start; // start address of a size class 20 | void* stop; // stop address of a size class 21 | void* current; // bumper pointer 22 | void* guardpage; // last guard page 23 | sll_t* head; // head of the free list 24 | uint64_t bitmap[ELE>>6]; // bitmap 25 | pthread_mutex_t lock; 26 | uint32_t size; // size of current sizeclass 27 | } cls_t; 28 | 29 | #ifdef RELEASE_MEM 30 | uint16_t *page_counter[INDEX]; 31 | #endif 32 | 33 | cls_t Class[INDEX]; 34 | uint32_t seed = 0; 35 | pthread_mutex_t global_lock; 36 | 37 | enum pool_state{null, init} STATE; 38 | 39 | /* *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org 40 | * See license for pcg32 in docs/pcg32-license.txt */ 41 | typedef struct { uint64_t state; uint64_t inc; } pcg32_random_t; 42 | __thread pcg32_random_t rng = {0x0, 0x0}; 43 | 44 | uint32_t pcg32_random_r(void) { 45 | uint64_t oldstate = rng.state; 46 | // Advance internal state 47 | rng.state = oldstate * 6364136223846793005ULL + (rng.inc|1); 48 | // Calculate output function (XSH RR), uses old state for max ILP 49 | uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; 50 | uint32_t rot = oldstate >> 59u; 51 | return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); 52 | } 53 | 54 | /* convert a size to its corresponding size Class */ 55 | uint8_t sz2cls(uint32_t sz) { 56 | 57 | if (sz >= (1 << 17)) 58 | return 255; 59 | 60 | if (sz < 128) { 61 | return ((sz>>(SLI_LOG2-1)) + ((sz&0x7) ? 1:0 )); 62 | } else { 63 | return ((((log2_64(sz)-MIN_EXP) << SLI_LOG2) | 64 | ((sz>> (log2_64(sz)-SLI_LOG2))& ~(1 << SLI_LOG2))) 65 | + ((((1<<(log2_64(sz)-SLI_LOG2)) - 1) & sz) ? 1:0 )); 66 | } 67 | } 68 | 69 | /* Find the size given a index */ 70 | uint32_t cls2sz(uint16_t cls) { 71 | if (cls < 16) { 72 | return (cls << (SLI_LOG2-1)); 73 | } else { 74 | uint8_t shift = (cls >> SLI_LOG2) + 6; 75 | return ((1U< PAGE_SIZE && (sz & (sz - 1)) == 0) 112 | align = sz; 113 | 114 | void* addr = slimguard_mmap(BUCKET_SIZE, align); // bucket start addr 115 | if(!addr) 116 | errx(-1, "Cannot allocate class %d data area\n", index); 117 | 118 | Class[index].head = NULL; // head of the sll contains free pointers 119 | Class[index].start = addr; // start address of the current bucket 120 | Class[index].current = Class[index].start; // bumper pointer 121 | Class[index].stop = (void *)((uint64_t)addr + BUCKET_SIZE); // upper 122 | // bound 123 | Class[index].size = cls2sz(index); // the size for current bucket 124 | 125 | for (int i = 0; i < BKT; i++) { 126 | Class[index].bucket[i] = Class[index].current; 127 | Class[index].current = (void *) ((uint64_t)Class[index].current + 128 | (uint64_t)Class[index].size); 129 | } 130 | 131 | Debug("BKT %d size: %d, start: %p\n", BKT, Class[index].size, 132 | Class[index].start); 133 | 134 | #ifdef RELEASE_MEM 135 | page_counter[index] = (uint16_t *)slimguard_mmap(4<<20, 0); 136 | if(!page_counter[index]) 137 | errx(-1, "Cannot allocate mem. for class %d page counter\n", index); 138 | #endif 139 | 140 | Debug("index: %u size: %u %p %p %p\n", index, Class[index].size, 141 | Class[index].start, Class[index].stop, Class[index].current); 142 | 143 | #ifdef GUARDPAGE 144 | void* next_page = (void *)((((uint64_t)Class[index].current >> 12) 145 | + 1 ) <<12); 146 | if (mprotect(next_page, PAGE_SIZE-1, PROT_NONE) == 0) { 147 | Class[index].guardpage = next_page; 148 | } else { 149 | perror("mprotect"); 150 | Error("[%x] %p %p %p\n", index, Class[index].start, next_page, 151 | Class[index].stop); 152 | exit(-1); 153 | } 154 | #else 155 | Class[index].guardpage = (uint64_t *)-1; 156 | #endif 157 | } 158 | } 159 | 160 | /* get next slot to fill in the bucket */ 161 | void *get_next(uint8_t index){ 162 | void* ret = Class[index].current; 163 | 164 | #ifdef GUARDPAGE 165 | if ((ret >= Class[index].guardpage) || 166 | ((uint64_t)ret + cls2sz(index) >= (uint64_t)Class[index].guardpage)){ 167 | ret = (void *)((((uint64_t )Class[index].guardpage >> 12) + 1) << 12); 168 | } 169 | #endif 170 | 171 | Class[index].current = (void *)((uint64_t)ret + (uint64_t)Class[index].size); 172 | 173 | if(Class[index].current >= Class[index].stop){ 174 | Error("not enough mem %u\n", Class[index].size); 175 | exit(-1); 176 | } 177 | 178 | /* We require slots managing power of two allocations to be aligned on 179 | * their sizes to properly serve memalign requests */ 180 | if(!(Class[index].size % PAGE_SIZE)) { 181 | uint64_t old_ret = (uint64_t)ret; 182 | 183 | ret = (void *)(((uint64_t)ret + (uint64_t)(Class[index].size) - 1) & 184 | ~((uint64_t)(Class[index].size) - 1)); 185 | Class[index].guardpage =(void *)((uint64_t)(Class[index].guardpage) 186 | + ((uint64_t)ret - old_ret)); 187 | Class[index].current =(void *)((uint64_t)(Class[index].current) 188 | + ((uint64_t)ret - old_ret)); 189 | } 190 | 191 | #ifdef GUARDPAGE 192 | if( (ret > Class[index].guardpage) || 193 | ((uint64_t)ret + Class[index].size >= 194 | (uint64_t)Class[index].guardpage)) { 195 | void * next_guard = (void *)((((uint64_t)Class[index].current >> 12) + 196 | GP ) <<12); 197 | 198 | if (mprotect(next_guard, PAGE_SIZE-1, PROT_NONE) == 0) { 199 | Class[index].guardpage = next_guard; 200 | } else { 201 | perror("mprotect"); 202 | exit(-1); 203 | } 204 | } 205 | #endif 206 | 207 | return ret; 208 | } 209 | 210 | /* select a random object in a bucket */ 211 | void* get_random_obj(uint8_t index) { 212 | uint16_t i = pcg32_random_r() % BKT; 213 | void *ret = Class[index].bucket[i]; 214 | 215 | if (!ret) { 216 | Error("%p %p\n", Class[index].current, Class[index].start); 217 | Error("Cannot get next object for class size(%x)\n\n", index); 218 | abort(); 219 | } 220 | 221 | Class[index].bucket[i] = get_next(index); 222 | 223 | return ret; 224 | } 225 | 226 | /* Hash a pointer to get canary value */ 227 | char HashPointer(const void* ptr) { 228 | long long Value = (long long)ptr; 229 | 230 | Value = ~Value + (Value << 15); 231 | Value = Value ^ (Value >> 12); 232 | Value = Value + (Value << 2); 233 | Value = Value ^ (Value >> 4); 234 | Value = Value * seed; 235 | Value = Value ^ (Value >> 16); 236 | 237 | return (char)Value; 238 | } 239 | 240 | /* put the canary to the end of each block, set it to MAGIC NUMBER */ 241 | void set_canary(void * ptr, uint8_t index) { 242 | char* end = (char *)((unsigned char *)ptr + Class[index].size - 1); 243 | *end = HashPointer(ptr); 244 | 245 | #ifdef DEBUG 246 | Canary("[%p] %p %x %u\n", ptr, end, *end, index); 247 | #endif 248 | } 249 | 250 | /* check the canary value */ 251 | void get_canary(const void *ptr, const uint8_t index) { 252 | char *end = (char *)((unsigned char *) ptr + Class[index].size - 1); 253 | 254 | #ifdef DEBUG 255 | Canary("[%p] %p %x\n", ptr, end, *end); 256 | #endif 257 | 258 | if(*end != HashPointer(ptr)) { 259 | Error("buffer overflow occured at %p, exiting now\n", ptr); 260 | Error("%x\n", HashPointer(ptr)); 261 | Error("[%p] %p %x %u %u\n", ptr, end, *end, Class[index].size, index); 262 | exit(-1); 263 | } 264 | } 265 | 266 | /* mark the bit map as "used" */ 267 | void mark_used(void *ptr, uint8_t index) { 268 | uint64_t i = (uint64_t)((char*)ptr - 269 | (char*)Class[index].start) / Class[index].size; 270 | uint32_t bitmap_index = i >> 6; 271 | uint8_t shift = i % (1<<6); 272 | 273 | Class[index].bitmap[bitmap_index] |= (1UL << shift); 274 | Debug("i: %lx bit: %u shift %u bitmap: %lx\n", i, bitmap_index, shift, 275 | Class[index].bitmap[bitmap_index]); 276 | } 277 | 278 | /* mark the bit map as "free" and check for potential vulunerabilities */ 279 | void mark_free(void *ptr, uint8_t index) { 280 | uint64_t i = (uint64_t)((char*)ptr - (char*)Class[index].start) / Class[index].size; 281 | uint32_t bitmap_index = i >> 6; 282 | uint8_t shift = i % (1<<6); 283 | 284 | if((Class[index].bitmap[bitmap_index] & (1UL << shift)) == 0) { 285 | Error("Double Free or Invalid Free @ %p\n", ptr); 286 | abort(); 287 | } 288 | 289 | Class[index].bitmap[bitmap_index] &= ~(1UL << shift); 290 | Debug("i: %lx bit: %u shift %u bitmap: %lx\n", i, bitmap_index, shift, 291 | Class[index].bitmap[bitmap_index]); 292 | } 293 | 294 | #ifdef RELEASE_MEM 295 | /* 296 | * if release_mem is defined, we will setup an array of counter, 297 | * each counter stores the number of object in a page, once this 298 | * number becomes 0, we will release the memory back to Operating System 299 | */ 300 | void increment_pc(void *ptr, uint8_t index) { 301 | uint64_t curr_page = ((uint64_t )ptr >> 12) <<12; 302 | uint16_t obj_size = Class[index].size; 303 | uint16_t *pc, pc_index; 304 | 305 | do { 306 | pc_index = (curr_page - (uint64_t)Class[index].start)/PAGE_SIZE; 307 | pc = (uint16_t *)((uint64_t)page_counter[index] + pc_index*sizeof(uint16_t)); 308 | *pc = *pc + 1; 309 | curr_page += PAGE_SIZE; 310 | } while((uint64_t) ptr+obj_size >= curr_page); 311 | 312 | //Debug("[%u]: %p \n", index, ptr); 313 | } 314 | 315 | void decrement_pc(void *ptr, uint8_t index) { 316 | uint64_t curr_page = ((uint64_t )ptr >> 12) <<12; 317 | uint16_t obj_size = Class[index].size; 318 | uint16_t *pc, pc_index; 319 | 320 | do { 321 | pc_index = (curr_page- (uint64_t)Class[index].start)/PAGE_SIZE; 322 | pc = (uint16_t *)((uint64_t)page_counter[index] + pc_index*sizeof(uint16_t)); 323 | *pc = *pc - 1; 324 | 325 | if (*pc == 0) 326 | madvise((void *)curr_page, PAGE_SIZE-1, MADV_DONTNEED); 327 | 328 | curr_page += PAGE_SIZE; 329 | } while((uint64_t) ptr + obj_size >= curr_page); 330 | } 331 | #endif 332 | 333 | /* given a pointer find the corresponding size class */ 334 | uint16_t find_sz_cls(const void *ptr) { 335 | static __thread int last_index = 0; 336 | 337 | for(int i=last_index; i (uint64_t)ptr)){ 340 | last_index = i; 341 | 342 | return i; 343 | } 344 | } 345 | 346 | for(int i=0; i (uint64_t)ptr)){ 349 | last_index = i; 350 | 351 | return i; 352 | } 353 | } 354 | 355 | return 255; 356 | } 357 | 358 | int log2_64 (uint64_t u) { 359 | if (u == 0) { return INT32_MIN; } 360 | return ((int64_t)63 - (int64_t)__builtin_clzll(u)); 361 | } 362 | 363 | /* SlimGuard malloc algorithm */ 364 | void* xxmalloc(size_t sz) { 365 | #ifdef USE_CANARY 366 | sz++; 367 | #endif 368 | 369 | uint64_t need = 0; 370 | void *ret = NULL; 371 | uint8_t index = 255; 372 | need = round_sz(sz); 373 | 374 | /* Can happen if sz is large enough */ 375 | if(!need) 376 | return NULL; 377 | 378 | if (need >= (1 << 17)) { 379 | Debug("sz %lu\n", need); 380 | ret = xxmalloc_large(need, 0); 381 | } else { 382 | if (STATE == null) { 383 | /* Lock here */ 384 | pthread_mutex_lock(&global_lock); 385 | init_bibop(); 386 | pthread_mutex_unlock(&global_lock); 387 | /* Lock end */ 388 | } 389 | 390 | index = sz2cls(need); 391 | 392 | if (index == 255) { 393 | perror("sz2cls"); 394 | return NULL; 395 | } 396 | 397 | /* Lock here */ 398 | pthread_mutex_lock(&(Class[index].lock)); 399 | 400 | if (Class[index].start == NULL) 401 | init_bucket(index); 402 | 403 | if (Class[index].head && Class[index].head->next) { 404 | ret = Class[index].head; 405 | Class[index].head = remove_head(Class[index].head); 406 | } else { 407 | ret = get_random_obj(index); 408 | } 409 | 410 | #ifdef RELEASE_MEM 411 | increment_pc(ret, index); 412 | #endif 413 | mark_used(ret, index); 414 | 415 | pthread_mutex_unlock(&(Class[index].lock)); 416 | /* Lock end */ 417 | 418 | #ifdef USE_CANARY 419 | set_canary(ret, index); 420 | #endif 421 | 422 | } 423 | 424 | return ret; 425 | } 426 | /* SlimGuard free */ 427 | void xxfree(void *ptr) { 428 | uint8_t index = 255; 429 | 430 | if (ptr == NULL) 431 | return; 432 | 433 | index = find_sz_cls(ptr); 434 | 435 | if (index == 255) { 436 | int i = xxfree_large(ptr); 437 | 438 | if (i == 1) { 439 | return; 440 | } else if (i == -1) { 441 | Error("invalid free/double free %p\n", ptr); 442 | abort(); 443 | return; 444 | } 445 | } 446 | 447 | #ifdef USE_CANARY 448 | get_canary(ptr, index); 449 | #endif 450 | 451 | #ifdef DESTROY_ON_FREE 452 | memset(ptr, 0, Class[index].size); 453 | #endif 454 | 455 | /* Lock here */ 456 | pthread_mutex_lock(&(Class[index].lock)); 457 | #ifdef RELEASE_MEM 458 | decrement_pc(ptr, index); 459 | #endif 460 | Class[index].head = add_head((sll_t *)ptr, Class[index].head); 461 | mark_free(ptr, index); 462 | pthread_mutex_unlock(&(Class[index].lock)); 463 | /* Lock end */ 464 | } 465 | 466 | void* xxrealloc(void *ptr, size_t size) { 467 | 468 | #ifdef USE_CANARY 469 | size++; 470 | #endif 471 | uint8_t index1, index2; 472 | void* ret = ptr; 473 | 474 | if(ptr == NULL) 475 | return xxmalloc(size); 476 | 477 | if(size == 0) { 478 | xxfree(ptr); 479 | return NULL; 480 | } 481 | 482 | index1 = find_sz_cls(ptr); // old size 483 | index2 = sz2cls(size); // new size 484 | 485 | size_t size1 = (index1 == 255) ? 486 | get_large_object_size(ptr) : Class[index1].size; 487 | 488 | if( index2 >= index1) { 489 | ret = xxmalloc(size); 490 | memcpy(ret, ptr, (size1 < size) ? size1 : size); 491 | xxfree(ptr); 492 | } 493 | 494 | return ret; 495 | } 496 | 497 | void* xxmemalign(size_t alignment, size_t size) { 498 | /* Here we use a small trick, for power of 2 sizes, each slot in the data 499 | * area is aligned to a multiple of its size so if alignment is larger than 500 | * size, we just malloc alignment to give it an address, if alignment is 501 | * smaller than size, we round the size to the next power of 2. When the 502 | * size needed cannot be managed as a small allocation, we use a large one 503 | * with alignment constraint. 504 | */ 505 | 506 | if(alignment &(alignment-1)){ 507 | Error("%lu is not a valid alignment, %s fails...\n", alignment, __func__); 508 | exit(-1); 509 | } 510 | 511 | #ifdef USE_CANARY 512 | size++; 513 | #endif 514 | 515 | if(alignment >= size) { 516 | if (alignment < (1 << 17)) 517 | return xxmalloc(alignment-1); 518 | else 519 | return xxmalloc_large(alignment, alignment); 520 | } else { 521 | #ifdef USE_CANARY 522 | uint64_t need = (1 << ((uint8_t)log2_64(size) + 1))-1; 523 | int need_large = (need+1) >= (1 << 17); 524 | #else 525 | uint64_t need = (1 << ((uint8_t)log2_64(size) + 1)); 526 | int need_large = (need) >= (1 << 17); 527 | #endif 528 | if(need_large) 529 | return xxmalloc_large(need, alignment); 530 | 531 | return xxmalloc(need); 532 | } 533 | } 534 | 535 | /* Only used for tests, with LD_PRELOAD and malloc_hooks calloc calls are 536 | * automatically translated to malloc calls */ 537 | void * xxcalloc(size_t nmemb, size_t size) { 538 | void *ret; 539 | 540 | ret = xxmalloc (nmemb * size); 541 | if (!ret) 542 | return ret; 543 | 544 | bzero (ret, nmemb * size); 545 | return ret; 546 | } 547 | 548 | /* high level SlimGuard API that is called by gnuwrapper */ 549 | void* slimguard_malloc(size_t size) { 550 | return xxmalloc(size); 551 | } 552 | 553 | void slimguard_free(void *ptr) { 554 | xxfree(ptr); 555 | } 556 | 557 | void* slimguard_realloc(void *ptr, size_t size) { 558 | return xxrealloc(ptr, size); 559 | } 560 | 561 | void* slimguard_memalign(size_t alignment, size_t size) { 562 | return xxmemalign(alignment, size); 563 | } 564 | 565 | -------------------------------------------------------------------------------- /src/sll.c: -------------------------------------------------------------------------------- 1 | /* sll.c 2 | * SlimGuard 3 | * Copyright (c) 2019, Beichen Liu, Virginia Tech 4 | * All rights reserved 5 | */ 6 | 7 | #include "debug.h" 8 | #include "sll.h" 9 | 10 | sll_t* add_head(sll_t* node, sll_t* slist) { 11 | 12 | if (slist == NULL) { 13 | slist = node; 14 | slist->next = NULL; 15 | } else { 16 | node->next = slist; 17 | slist = node; 18 | } 19 | 20 | return slist; 21 | } 22 | 23 | sll_t* remove_head(sll_t* slist) { 24 | 25 | if ((slist == NULL) | (slist->next == NULL)) 26 | return NULL; 27 | 28 | slist = slist->next; 29 | return slist; 30 | } 31 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.7.2) # CMake version check 2 | project(SlimGuard) 3 | 4 | include_directories(../include) 5 | 6 | set(CMAKE_C_COMPILER g++) 7 | 8 | set(debug off) 9 | set(canary on) 10 | set(release-memory on) 11 | set(guardpage on) 12 | set(destroy-on-free on) 13 | 14 | include_directories(../include/) 15 | 16 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-deprecated-declarations -O0 -g") 17 | 18 | if(debug) 19 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -DDEBUG") 20 | endif(debug) 21 | 22 | if(canary) 23 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_CANARY") 24 | endif(canary) 25 | 26 | if(release-memory) 27 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DRELEASE_MEM") 28 | endif(release-memory) 29 | 30 | if(guardpage) 31 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DGUARDPAGE") 32 | endif(guardpage) 33 | 34 | if(destroy-on-free) 35 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDESTROY_ON_FREE") 36 | endif(destroy-on-free) 37 | 38 | set(debug ../include/debug.h) 39 | set(catch catch.hpp) 40 | 41 | set(slimguard-large ${debug} ../test/slimguard-large-test.c) 42 | set(memalign ${debug} ../test/memalign.c) 43 | set(memalign-free ${debug} ../test/memalign-free.c) 44 | set(large-alloc ${debug} ../test/large-alloc.c) 45 | set(memory-content ${debug} ../test/memory-content.c) 46 | set(slimguard-test ${debug} ../test/slimguard-test.c) 47 | set(malloc-test ${debug} ../test/malloc-test.c) 48 | set(mimalloc-test ${debug} ../test/mimalloc-test.c) 49 | set(memory-content ${debug} ../test/memory-content.c) 50 | set(calloc ${debug} ../test/calloc.c) 51 | set(realloc ${debug} ../test/realloc.c) 52 | set(very-large ${debug} ../test/very-large.c) 53 | set(slimguard-base ${debug} ../include/slimguard.h 54 | ../src/slimguard.c 55 | ../src/slimguard-large.c 56 | ../src/sll.c 57 | ../include/slimguard-mmap.h 58 | ../src/slimguard-mmap.c 59 | ../src/slimguard-large.c 60 | ../include/slimguard-large.h) 61 | 62 | enable_testing() 63 | 64 | add_executable(slimguard-large-test ${slimguard-large} ${slimguard-base} ${catch}) 65 | add_executable(slimguard-test ${slimguard-test} ${slimguard-base} ${catch}) 66 | add_executable(memalign ${memalign} ${slimguard-base} ${catch}) 67 | add_executable(memalign-free ${memalign-free} ${slimguard-base} ${catch}) 68 | add_executable(large-alloc ${large-alloc} ${slimguard-base} ${catch}) 69 | add_executable(memory-content ${memory-content} ${slimguard-base} ${catch}) 70 | add_executable(malloc-test ${malloc-test} ${slimguard-base} ${catch}) 71 | add_executable(mimalloc-test ${mimalloc-test} ${slimguard-base} ${catch}) 72 | add_executable(calloc ${calloc} ${slimguard-base} ${catch}) 73 | add_executable(realloc ${realloc} ${slimguard-base} ${catch}) 74 | add_executable(very-large ${very-large} ${slimguard-base} ${catch}) 75 | 76 | target_link_libraries(mimalloc-test pthread) 77 | 78 | add_test(slimguard-large-test slimguard-large-test) 79 | add_test(slimguard-test slimguard-test) 80 | add_test(memalign memalign) 81 | add_test(memalign-free memalign-free) 82 | add_test(large-alloc large-alloc) 83 | add_test(memory-content memory-content) 84 | add_test(malloc-test malloc-test) 85 | add_test(mimalloc-test mimalloc-test) 86 | add_test(calloc calloc) 87 | add_test(realloc realloc) 88 | add_test(very-large very-large) 89 | -------------------------------------------------------------------------------- /test/calloc.c: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | #include "../include/slimguard.h" 4 | #include "../include/slimguard-large.h" 5 | #include "../include/sll.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define NMEMB 10 13 | #define SIZE 128 14 | 15 | TEST_CASE("calloc", "[slimguard]") { 16 | void *ptr = xxcalloc(NMEMB, SIZE); 17 | REQUIRE(ptr); 18 | memset(ptr, 0x0, SIZE*NMEMB); 19 | xxfree(ptr); 20 | } 21 | -------------------------------------------------------------------------------- /test/large-alloc.c: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | #include "../include/slimguard.h" 4 | #include "../include/slimguard-large.h" 5 | #include "../include/sll.h" 6 | 7 | #define ALLOC_SIZE (5*1024*1024) 8 | 9 | TEST_CASE("large-alloc", "[slimguard]") { 10 | void *ptr = xxmalloc(ALLOC_SIZE); 11 | REQUIRE(ptr); 12 | memset(ptr, 0x0, ALLOC_SIZE); 13 | xxfree(ptr); 14 | } 15 | -------------------------------------------------------------------------------- /test/malloc-test.c: -------------------------------------------------------------------------------- 1 | /* malloc-test.c 2 | * by Wolfram Gloger 1995, 1996 3 | * 4 | * This program is provided `as is', there is no warranty. 5 | */ 6 | 7 | #define CATCH_CONFIG_MAIN 8 | #include "catch.hpp" 9 | #include "../include/slimguard.h" 10 | #include "../include/slimguard-large.h" 11 | #include "../include/sll.h" 12 | 13 | #if !defined(__STDC__) 14 | #define __STDC__ 1 15 | #endif 16 | 17 | #include 18 | #include 19 | 20 | #if !defined(_WIN32) 21 | #include 22 | #include 23 | #include 24 | #include 25 | #endif 26 | 27 | #ifndef MEMORY 28 | #define MEMORY 4000000l 29 | #endif 30 | #ifndef BINS_MAX 31 | #define BINS_MAX 32768 32 | #endif 33 | #define SBINS_MAX 1024 34 | #define SIZE 4024 35 | #define I_MAX 5000 36 | #ifndef I_AVERAGE 37 | #define I_AVERAGE 200 38 | #endif 39 | #define ACTIONS_MAX 50 40 | #ifndef SBRK_AVG 41 | #define SBRK_AVG 0 42 | #endif 43 | #ifndef MMAP_THRESH 44 | #define MMAP_THRESH 0 45 | #endif 46 | #ifndef TEST 47 | #define TEST 4 /* minimal testing */ 48 | #endif 49 | #ifndef TEST_INC 50 | #define TEST_INC 2047 51 | #endif 52 | #ifndef PAGE_SIZE 53 | #if defined(__i386__) || defined(__sparc__) || defined(mips) || defined(_WIN32) 54 | #define PAGE_SIZE 4096 55 | #elif defined(__alpha__) 56 | #define PAGE_SIZE 8192 57 | #elif defined(__SVR4) 58 | #define PAGE_SIZE 8192 59 | #else 60 | #define PAGE_SIZE 4096 /* default */ 61 | #endif 62 | #endif 63 | #define RANDOM(s) (lran2(0) % (s)) 64 | 65 | /* All probabilities are parts in 1024. */ 66 | #ifndef PROB_MEMALIGN 67 | #define PROB_MEMALIGN 0 68 | #endif 69 | #ifndef PROB_REALLOC 70 | #define PROB_REALLOC 48 71 | #endif 72 | #ifndef PROB_CALLOC 73 | #define PROB_CALLOC 0 74 | #endif 75 | 76 | struct bin { 77 | unsigned char *ptr; 78 | unsigned long size; 79 | } m[BINS_MAX], sm[SBINS_MAX]; 80 | 81 | unsigned long size = SIZE, bins=0, sbins=0; 82 | unsigned long total_size=0, total_size_max=0; 83 | unsigned char *base_ptr; 84 | unsigned long base_save; 85 | 86 | long 87 | #if __STDC__ 88 | lran2(long seed) 89 | #else 90 | lran2(seed) long seed; 91 | #endif 92 | #define LRAN2_MAX 714025l /* constants for portable */ 93 | #define IA 1366l /* random number generator */ 94 | #define IC 150889l /* (see Numerical Recipes p. 211) */ 95 | { 96 | static int first = 1; 97 | static long x, y, v[97]; 98 | int j; 99 | 100 | if(seed || first) { 101 | first = 0; 102 | x = (IC - seed) % LRAN2_MAX; 103 | if(x < 0) x = -x; 104 | for(j=0; j<97; j++) { 105 | x = (IA*x + IC) % LRAN2_MAX; 106 | v[j] = x; 107 | } 108 | x = (IA*x + IC) % LRAN2_MAX; 109 | y = x; 110 | } 111 | j = y % 97; 112 | y = v[j]; 113 | x = (IA*x + IC) % LRAN2_MAX; 114 | v[j] = x; 115 | return y; 116 | } 117 | #undef IA 118 | #undef IC 119 | 120 | void 121 | #if __STDC__ 122 | mem_init(unsigned char *ptr, unsigned long size) 123 | #else 124 | mem_init(ptr, size) unsigned char *ptr; unsigned long size; 125 | #endif 126 | { 127 | unsigned long i, j; 128 | 129 | if(size == 0) return; 130 | if(size > sizeof(unsigned long)) { 131 | /* Try the complete initial word. */ 132 | *(unsigned long *)ptr = (unsigned long)ptr ^ size; 133 | i = TEST_INC; 134 | } else 135 | i = 0; 136 | for(; i>8)) & 0xFF); 139 | } 140 | j = (unsigned long)ptr ^ (size-1); 141 | ptr[size-1] = ((j ^ (j>>8)) & 0xFF); 142 | } 143 | 144 | int 145 | #if __STDC__ 146 | mem_check(unsigned char *ptr, unsigned long size) 147 | #else 148 | mem_check(ptr, size) unsigned char *ptr; unsigned long size; 149 | #endif 150 | { 151 | unsigned long i, j; 152 | 153 | if(size == 0) return 0; 154 | if(size > sizeof(unsigned long)) { 155 | if(*(unsigned long *)ptr != ((unsigned long)ptr ^ size)) { 156 | printf ("failed size check: expected %lx, found %lx!\n", 157 | ((unsigned long) ptr ^ size), *(unsigned long *) ptr); 158 | return 1; 159 | } 160 | i = TEST_INC; 161 | } else 162 | i = 0; 163 | for(; i>8)) & 0xFF)) return 2; 166 | } 167 | j = (unsigned long)ptr ^ (size-1); 168 | if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) { 169 | printf ("failed last byte check: expected %lx, found %d!\n", 170 | ((unsigned long) ((j ^ (j>>8)) & 0xFF)), ptr[size-1]); 171 | return 3; 172 | } 173 | return 0; 174 | } 175 | 176 | long 177 | #if __STDC__ 178 | random_size(long max) 179 | #else 180 | random_size(max) long max; 181 | #endif 182 | { 183 | long r1, r2, r, max_pages; 184 | 185 | max_pages = max/PAGE_SIZE; 186 | if(max_pages > 0) { 187 | r1 = RANDOM(1024); 188 | r2 = (r1 & 7)*4; 189 | if(r1 < 512) { 190 | /* small value near power of two */ 191 | r = (1L << (r1 >> 6)) + r2; 192 | } else if(r1 < 512+20) { 193 | /* value near a multiple of the page size */ 194 | r = (RANDOM(max_pages)+1)*PAGE_SIZE + r2 - 16; 195 | /*printf("r = %4lx\n", r);*/ 196 | } else r = RANDOM(max) + 1; 197 | } else r = RANDOM(max) + 1; 198 | /*if(r <= 0) exit(-1);*/ 199 | return r; 200 | } 201 | 202 | void 203 | #if __STDC__ 204 | bin_alloc(struct bin *m) 205 | #else 206 | bin_alloc(m) struct bin *m; 207 | #endif 208 | { 209 | long r, key; 210 | unsigned long sz; 211 | 212 | #if TEST > 0 213 | if(mem_check(m->ptr, m->size)) { 214 | printf("bin_alloc: memory corrupt at %p, size=%lu!\n", m->ptr, m->size); 215 | exit(1); 216 | } 217 | #endif 218 | total_size -= m->size; 219 | r = RANDOM(1024); 220 | if(r < PROB_MEMALIGN) { 221 | #if !defined(_WIN32) 222 | if(m->size > 0) xxfree(m->ptr); 223 | m->size = random_size(size); 224 | #if PROB_MEMALIGN 225 | m->ptr = (unsigned char *)xxmemalign(4 << RANDOM(8), m->size); 226 | #endif 227 | 228 | #endif 229 | } else if(r < (PROB_MEMALIGN + PROB_REALLOC)) { 230 | if(m->size == 0) { 231 | #ifndef __sparc__ 232 | m->ptr = NULL; 233 | #else 234 | /* SunOS4 does not realloc() a NULL pointer */ 235 | m->ptr = (unsigned char *)xxmalloc(1); 236 | #endif 237 | } 238 | #if TEST > 2 239 | key = RANDOM(256); 240 | sz = m->size; 241 | for(r=0; (long unsigned)rptr[r] = (r ^ key) & 0xFF; 242 | #endif 243 | m->size = random_size(size); 244 | /*printf("realloc %d\n", (int)m->size);*/ 245 | m->ptr = (unsigned char *)xxrealloc(m->ptr, m->size); 246 | #if TEST > 2 247 | if(m->size < sz) sz = m->size; 248 | for(r=0; (long unsigned)rptr[r] != ((r ^ key) & 0xFF)) { 250 | printf("realloc bug !\n"); 251 | exit(1); 252 | } 253 | #endif 254 | } else if(r < (PROB_MEMALIGN + PROB_REALLOC + PROB_CALLOC)) { 255 | if(m->size > 0) xxfree(m->ptr); 256 | m->size = random_size(size); 257 | m->ptr = (unsigned char *)calloc(m->size, 1); 258 | #if TEST > 2 259 | for(r=0; (long unsigned)rsize; r++) 260 | if(m->ptr[r] != '\0') { 261 | printf("calloc bug !\n"); 262 | exit(1); 263 | } 264 | #endif 265 | } else { /* normal malloc call */ 266 | if(m->size > 0) xxfree(m->ptr); 267 | m->size = random_size(size); 268 | m->ptr = (unsigned char *)xxmalloc(m->size); 269 | } 270 | if(!m->ptr) { 271 | printf("out of memory!\n"); 272 | exit(1); 273 | } 274 | total_size += m->size; 275 | if(total_size > total_size_max) total_size_max = total_size; 276 | #if TEST > 0 277 | mem_init(m->ptr, m->size); 278 | #endif 279 | if(m->ptr < base_ptr) { 280 | #ifdef VERBOSE 281 | printf("hmmm, allocating below brk...\n"); 282 | #endif 283 | base_ptr = m->ptr; 284 | } 285 | } 286 | 287 | void 288 | #if __STDC__ 289 | bin_free(struct bin *m) 290 | #else 291 | bin_free(m) struct bin *m; 292 | #endif 293 | { 294 | if(m->size == 0) return; 295 | #if TEST > 0 296 | if(mem_check(m->ptr, m->size)) { 297 | printf("bin_free: memory corrupt!\n"); 298 | exit(1); 299 | } 300 | #endif 301 | total_size -= m->size; 302 | xxfree(m->ptr); 303 | m->size = 0; 304 | } 305 | 306 | void 307 | bin_test() 308 | { 309 | unsigned int b; 310 | int v; 311 | // printf ("bin_test.\n"); 312 | 313 | for(b=0; b= 1000000) { 345 | total_usec -= 1000000; 346 | total_sec++; 347 | } 348 | printf(" t=%ld.%06ldsec", total_sec, total_usec); 349 | #endif 350 | } 351 | 352 | #if __STDC__ 353 | TEST_CASE("malloc-test", "[slimguard]") 354 | #else 355 | main(argc, argv) int argc; char *argv[]; 356 | #endif 357 | { 358 | int i, j, next_i, count, max=I_MAX, actions; 359 | unsigned int b; 360 | long sbrk_max, sum; 361 | double sbrk_used_sum, total_size_sum; 362 | // void* dummy = 0; 363 | 364 | int argc = 3; 365 | const char * const argv[] = {"hello", "100000", "1048576" }; 366 | 367 | if(argc > 1) max = atoi(argv[1]); 368 | if(argc > 2) size = atoi(argv[2]); 369 | lran2((long)max ^ size); 370 | bins = (MEMORY/size)*4; 371 | if(bins > BINS_MAX) bins = BINS_MAX; 372 | #if 0 // FIX ME? Disable sbrk... 373 | base_ptr = (unsigned char *)sbrk(0); 374 | sum = (long)base_ptr % PAGE_SIZE; 375 | if(sum > 0) { 376 | if((char *)sbrk((long)PAGE_SIZE - sum) == (char *)-1) exit(1); 377 | base_ptr += (long)PAGE_SIZE - sum; 378 | /*printf("base_ptr = %lx\n", (long)base_ptr);*/ 379 | } 380 | /* attempt to fill up the region below the initial brk */ 381 | for(i=0; i<10000; i++) { 382 | dummy = xxmalloc(1); 383 | if(dummy >= (void*)base_ptr) break; 384 | } 385 | xxfree(dummy); 386 | base_save = ((unsigned long)base_ptr >> 24) << 24; 387 | #endif 388 | 389 | #if MMAP_THRESH > 0 390 | if(!mallopt(-3, MMAP_THRESH)) printf("mallopt failed!\n"); 391 | if(!mallopt(-4, 200)) printf("mallopt failed!\n"); 392 | #endif 393 | #ifdef VERBOSE 394 | printf("# mmap_thresh=%d\n", MMAP_THRESH); 395 | printf("# bins=%d max=%d size=%d\n", bins, max, size); 396 | printf("# base=%lx\n", base_save); 397 | #endif 398 | for(b=0; b 1 406 | bin_test(); 407 | #endif 408 | #ifdef MSTATS 409 | malloc_stats(); 410 | #endif 411 | actions = RANDOM(ACTIONS_MAX); 412 | for(j=0; j 3 416 | bin_test(); 417 | #endif 418 | } 419 | i += actions; 420 | #ifdef AFTER_FREE 421 | AFTER_FREE; 422 | #endif 423 | #if SBRK_AVG > 0 424 | if(sbins0 && sm[sbins].ptr==(sm[sbins-1].ptr+sm[sbins-1].size)) { 429 | sm[sbins-1].size += sm[sbins].size; 430 | sbins--; 431 | } 432 | #ifdef VERBOSE 433 | printf("sbrk #%d %p %ld\n", sbins, sm[sbins].ptr, sm[sbins].size); 434 | #endif 435 | #if TEST > 0 436 | mem_init(sm[sbins].ptr, sm[sbins].size); 437 | #endif 438 | sbins++; 439 | } 440 | #endif 441 | actions = RANDOM(ACTIONS_MAX); 442 | for(j=0; j 3 446 | bin_test(); 447 | #endif 448 | } 449 | i += actions; 450 | if(i >= next_i) { /* gather statistics */ 451 | count++; 452 | #if !defined(_WIN32) 453 | sum = (long)sbrk(0); 454 | #else 455 | sum = 0; 456 | #endif 457 | if(sum > sbrk_max) sbrk_max = sum; 458 | sbrk_used_sum += sum; 459 | total_size_sum += (double)total_size; 460 | #ifdef VERBOSE 461 | printf("%8d %7lu\n", i, total_size); 462 | #endif 463 | next_i += I_AVERAGE; 464 | } 465 | } 466 | 467 | /* Correct sbrk values. */ 468 | sbrk_max -= (long)base_ptr; 469 | sbrk_used_sum -= (double)count*(long)base_ptr; 470 | #ifdef VERBOSE 471 | printf("# initial brk: %lx\n", (long)base_ptr); 472 | printf("# max. sbrk()'ed memory: %ld bytes\n", sbrk_max); 473 | printf("# avg. sbrk()'ed memory: %ld bytes\n", 474 | (long)(sbrk_used_sum/count)); 475 | printf("# current size allocated: %ld bytes\n", total_size); 476 | printf("# maximum size allocated: %ld bytes\n", total_size_max); 477 | printf("# average size allocated: %.1f bytes\n", total_size_sum/count); 478 | printf("# current heap waste: %.2f%%\n", 479 | (1.0 - (double)total_size_max/sbrk_max)*100.0); 480 | printf("# average heap waste: %.2f%%\n", 481 | (1.0 - (double)total_size_sum/sbrk_used_sum)*100.0); 482 | printf("# total sbrk calls performed: %d\n", sbins); 483 | #else 484 | printf("size=%7ld waste=%7.3f%%", size, 485 | /* (1.0 - (double)total_size_max/sbrk_max)*100.0, */ 486 | (1.0 - (double)total_size_sum/sbrk_used_sum)*100.0); 487 | print_times(); 488 | printf("\n"); 489 | #endif 490 | } 491 | 492 | /* 493 | * Local variables: 494 | * tab-width:4 495 | * compile-command: "gcc -Wall malloc-test.c -o malloc-test" 496 | * End: 497 | */ 498 | 499 | -------------------------------------------------------------------------------- /test/memalign-free.c: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | #include "../include/slimguard.h" 4 | #include "../include/slimguard-large.h" 5 | #include "../include/sll.h" 6 | 7 | TEST_CASE("memalign", "[slimguard]") 8 | { 9 | void *ptr = xxmemalign(128, 128); 10 | REQUIRE(ptr); 11 | REQUIRE(!((uint64_t)ptr % 128)); 12 | memset(ptr, 0x0, 128); 13 | xxfree(ptr); 14 | } 15 | -------------------------------------------------------------------------------- /test/memalign-standalone/.gdb_history: -------------------------------------------------------------------------------- 1 | set environment LD_PRELOAD ../../libSlimGuard.so 2 | break xxmalloc if sz == 0x3FFF 3 | sharedlibrary ../../libSlimGuard.so 4 | sharedlibrary ../../lib 5 | pwd 6 | sharedlibrary ../../libSlimGuard.so 7 | sharedlibrary libSlimGuard.so 8 | run 9 | br xxfree 10 | br free 11 | set environment LD_PRELOAD ../../libSlimGuard.so 12 | run 13 | cls2sz 14 | p cls2sz 15 | p sz2cls 16 | dis sz2cls 17 | dissassemble sz2cls 18 | c sz2cls 19 | p sz2cls(1) 20 | set environment LD_PRELOAD ../../libSlimGuard.so 21 | br free 22 | run 23 | p cl2sz 24 | -------------------------------------------------------------------------------- /test/memalign-standalone/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CFLAGS=-g 3 | LDFLAGS=-lpthread 4 | PROG=memalign 5 | SRC=memalign.c 6 | 7 | all: $(PROG) 8 | 9 | $(PROG): $(SRC) 10 | $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) 11 | 12 | run: $(PROG) 13 | LD_PRELOAD=$(PWD)/../../libSlimGuard.so ./$(PROG) 14 | 15 | clean: 16 | rm -rf *.o $(PROG) 17 | -------------------------------------------------------------------------------- /test/memalign-standalone/memalign.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define MAX_ALIGNMENT (1024*1024) 9 | 10 | int main(int argc, char **argv) { 11 | for(int alignment = 16; alignment<=MAX_ALIGNMENT; alignment*=2) { 12 | 13 | void *ptr = memalign(alignment, alignment); 14 | assert(ptr); 15 | printf("Required size 0x%x with alignment 0x%x got pointer @%p\n", 16 | alignment, alignment, ptr); 17 | assert(!((uint64_t)ptr % alignment)); 18 | memset(ptr, 0x0, alignment); 19 | free(ptr); 20 | 21 | void *ptr2 = memalign(alignment, alignment*2); 22 | printf("Required size 0x%x with alignment 0x%x got pointer @%p\n", 23 | alignment*2, alignment, ptr2); 24 | assert(ptr2); 25 | assert(!((uint64_t)ptr2 % alignment)); 26 | memset(ptr2, 0x0, alignment*2); 27 | free(ptr2); 28 | 29 | void *ptr3 = memalign(alignment, alignment/2); 30 | printf("Required size 0x%x with alignment 0x%x got pointer @%p\n", 31 | alignment/2, alignment, ptr3); 32 | assert(ptr3); 33 | assert(!((uint64_t)ptr3 % alignment)); 34 | memset(ptr3, 0x0, alignment/2); 35 | free(ptr3); 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/memalign.c: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | #include "../include/slimguard.h" 4 | #include "../include/slimguard-large.h" 5 | #include "../include/sll.h" 6 | 7 | #define MAX_ALIGNMENT (1024*1024) 8 | #define ITERATIONS 500 9 | #define VERBOSE 0 10 | 11 | TEST_CASE("memalign", "[slimguard]") 12 | { 13 | for(int alignment = 16; alignment<=MAX_ALIGNMENT; alignment*=2) { 14 | void *ptrs[ITERATIONS]; 15 | void *ptrs2[ITERATIONS]; 16 | void *ptrs3[ITERATIONS]; 17 | 18 | for(int i=0; i 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifndef USE_STD_MALLOC 33 | #include 34 | #endif 35 | 36 | // > mimalloc-test-stress [THREADS] [SCALE] [ITER] 37 | // 38 | // argument defaults 39 | static int THREADS = 32; // more repeatable if THREADS <= #processors 40 | static int SCALE = 10; // scaling factor 41 | static int ITER = 50; // N full iterations destructing and re-creating all threads 42 | 43 | // static int THREADS = 8; // more repeatable if THREADS <= #processors 44 | // static int SCALE = 100; // scaling factor 45 | 46 | #define STRESS // undefine for leak test 47 | 48 | static bool allow_large_objects = true; // allow very large objects? 49 | static size_t use_one_size = 0; // use single object size of `N * sizeof(uintptr_t)`? 50 | 51 | 52 | #ifdef USE_STD_MALLOC 53 | #define custom_calloc(n,s) calloc(n,s) 54 | #define custom_realloc(p,s) realloc(p,s) 55 | #define custom_free(p) free(p) 56 | #else 57 | #define custom_calloc(n,s) mi_calloc(n,s) 58 | #define custom_realloc(p,s) mi_realloc(p,s) 59 | #define custom_free(p) mi_free(p) 60 | #endif 61 | 62 | // transfer pointer between threads 63 | #define TRANSFERS (1000) 64 | static volatile void* transfer[TRANSFERS]; 65 | 66 | 67 | #if (UINTPTR_MAX != UINT32_MAX) 68 | const uintptr_t cookie = 0xbf58476d1ce4e5b9UL; 69 | #else 70 | const uintptr_t cookie = 0x1ce4e5b9UL; 71 | #endif 72 | 73 | static void* atomic_exchange_ptr(volatile void** p, void* newval); 74 | 75 | typedef uintptr_t* random_t; 76 | 77 | static uintptr_t pick(random_t r) { 78 | uintptr_t x = *r; 79 | #if (UINTPTR_MAX > UINT32_MAX) 80 | // by Sebastiano Vigna, see: 81 | x ^= x >> 30; 82 | x *= 0xbf58476d1ce4e5b9UL; 83 | x ^= x >> 27; 84 | x *= 0x94d049bb133111ebUL; 85 | x ^= x >> 31; 86 | #else 87 | // by Chris Wellons, see: 88 | x ^= x >> 16; 89 | x *= 0x7feb352dUL; 90 | x ^= x >> 15; 91 | x *= 0x846ca68bUL; 92 | x ^= x >> 16; 93 | #endif 94 | *r = x; 95 | return x; 96 | } 97 | 98 | static bool chance(size_t perc, random_t r) { 99 | return (pick(r) % 100 <= perc); 100 | } 101 | 102 | static void* alloc_items(size_t items, random_t r) { 103 | if (chance(1, r)) { 104 | if (chance(1, r) && allow_large_objects) items *= 10000; // 0.01% giant 105 | else if (chance(10, r) && allow_large_objects) items *= 1000; // 0.1% huge 106 | else items *= 100; // 1% large objects; 107 | } 108 | if (items == 40) items++; // pthreads uses that size for stack increases 109 | if (use_one_size > 0) items = (use_one_size / sizeof(uintptr_t)); 110 | if (items==0) items = 1; 111 | uintptr_t* p = (uintptr_t*)custom_calloc(items,sizeof(uintptr_t)); 112 | if (p != NULL) { 113 | for (uintptr_t i = 0; i < items; i++) { 114 | p[i] = (items - i) ^ cookie; 115 | } 116 | } 117 | return p; 118 | } 119 | 120 | static void free_items(void* p) { 121 | if (p != NULL) { 122 | uintptr_t* q = (uintptr_t*)p; 123 | uintptr_t items = (q[0] ^ cookie); 124 | for (uintptr_t i = 0; i < items; i++) { 125 | if ((q[i] ^ cookie) != items - i) { 126 | fprintf(stderr, "memory corruption at block %p at %zu\n", p, i); 127 | abort(); 128 | } 129 | } 130 | } 131 | custom_free(p); 132 | } 133 | 134 | 135 | static void stress(intptr_t tid) { 136 | //bench_start_thread(); 137 | uintptr_t r = (tid * 43); // rand(); 138 | const size_t max_item_shift = 5; // 128 139 | const size_t max_item_retained_shift = max_item_shift + 2; 140 | size_t allocs = 100 * ((size_t)SCALE) * (tid % 8 + 1); // some threads do more 141 | size_t retain = allocs / 2; 142 | void** data = NULL; 143 | size_t data_size = 0; 144 | size_t data_top = 0; 145 | void** retained = (void**)custom_calloc(retain,sizeof(void*)); 146 | size_t retain_top = 0; 147 | 148 | while (allocs > 0 || retain > 0) { 149 | if (retain == 0 || (chance(50, &r) && allocs > 0)) { 150 | // 50%+ alloc 151 | allocs--; 152 | if (data_top >= data_size) { 153 | data_size += 100000; 154 | data = (void**)custom_realloc(data, data_size * sizeof(void*)); 155 | } 156 | data[data_top++] = alloc_items(1ULL << (pick(&r) % max_item_shift), &r); 157 | } 158 | else { 159 | // 25% retain 160 | retained[retain_top++] = alloc_items( 1ULL << (pick(&r) % max_item_retained_shift), &r); 161 | retain--; 162 | } 163 | if (chance(66, &r) && data_top > 0) { 164 | // 66% free previous alloc 165 | size_t idx = pick(&r) % data_top; 166 | free_items(data[idx]); 167 | data[idx] = NULL; 168 | } 169 | if (chance(25, &r) && data_top > 0) { 170 | // 25% exchange a local pointer with the (shared) transfer buffer. 171 | size_t data_idx = pick(&r) % data_top; 172 | size_t transfer_idx = pick(&r) % TRANSFERS; 173 | void* p = data[data_idx]; 174 | void* q = atomic_exchange_ptr(&transfer[transfer_idx], p); 175 | data[data_idx] = q; 176 | } 177 | } 178 | // free everything that is left 179 | for (size_t i = 0; i < retain_top; i++) { 180 | free_items(retained[i]); 181 | } 182 | for (size_t i = 0; i < data_top; i++) { 183 | free_items(data[i]); 184 | } 185 | custom_free(retained); 186 | custom_free(data); 187 | //bench_end_thread(); 188 | } 189 | 190 | static void run_os_threads(size_t nthreads, void (*entry)(intptr_t tid)); 191 | 192 | static void test_stress(void) { 193 | uintptr_t r = rand(); 194 | for (int n = 0; n < ITER; n++) { 195 | run_os_threads(THREADS, &stress); 196 | for (int i = 0; i < TRANSFERS; i++) { 197 | if (chance(50, &r) || n + 1 == ITER) { // free all on last run, otherwise free half of the transfers 198 | void* p = atomic_exchange_ptr(&transfer[i], NULL); 199 | free_items(p); 200 | } 201 | } 202 | // mi_collect(false); 203 | #ifndef NDEBUG 204 | if ((n + 1) % 10 == 0) { printf("- iterations left: %3d\n", ITER - (n + 1)); } 205 | #endif 206 | } 207 | } 208 | 209 | #ifndef STRESS 210 | static void leak(intptr_t tid) { 211 | uintptr_t r = rand(); 212 | void* p = alloc_items(1 /*pick(&r)%128*/, &r); 213 | if (chance(50, &r)) { 214 | intptr_t i = (pick(&r) % TRANSFERS); 215 | void* q = atomic_exchange_ptr(&transfer[i], p); 216 | free_items(q); 217 | } 218 | } 219 | 220 | static void test_leak(void) { 221 | for (int n = 0; n < ITER; n++) { 222 | run_os_threads(THREADS, &leak); 223 | mi_collect(false); 224 | #ifndef NDEBUG 225 | if ((n + 1) % 10 == 0) { printf("- iterations left: %3d\n", ITER - (n + 1)); } 226 | #endif 227 | } 228 | } 229 | #endif 230 | 231 | TEST_CASE("mimalloc-test", "[slimguard]") 232 | { 233 | // > mimalloc-test-stress [THREADS] [SCALE] [ITER] 234 | int argc = 1; 235 | const char * const argv[] = {"hello"}; 236 | 237 | if (argc >= 2) { 238 | char* end; 239 | long n = strtol(argv[1], &end, 10); 240 | if (n > 0) THREADS = n; 241 | } 242 | if (argc >= 3) { 243 | char* end; 244 | long n = (strtol(argv[2], &end, 10)); 245 | if (n > 0) SCALE = n; 246 | } 247 | if (argc >= 4) { 248 | char* end; 249 | long n = (strtol(argv[3], &end, 10)); 250 | if (n > 0) ITER = n; 251 | } 252 | printf("Using %d threads with a %d%% load-per-thread and %d iterations\n", THREADS, SCALE, ITER); 253 | //int res = mi_reserve_huge_os_pages(4,1); 254 | //printf("(reserve huge: %i\n)", res); 255 | 256 | //bench_start_program(); 257 | 258 | // Run ITER full iterations where half the objects in the transfer buffer survive to the next round. 259 | srand(0x7feb352d); 260 | // mi_stats_reset(); 261 | #ifdef STRESS 262 | test_stress(); 263 | #else 264 | test_leak(); 265 | #endif 266 | 267 | #ifndef USE_STD_MALLOC 268 | // mi_collect(true); 269 | mi_stats_print(NULL); 270 | #endif 271 | //bench_end_program(); 272 | } 273 | 274 | 275 | static void (*thread_entry_fun)(intptr_t) = &stress; 276 | 277 | #ifdef _WIN32 278 | 279 | #include 280 | 281 | static DWORD WINAPI thread_entry(LPVOID param) { 282 | thread_entry_fun((intptr_t)param); 283 | return 0; 284 | } 285 | 286 | static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { 287 | thread_entry_fun = fun; 288 | DWORD* tids = (DWORD*)custom_calloc(nthreads,sizeof(DWORD)); 289 | HANDLE* thandles = (HANDLE*)custom_calloc(nthreads,sizeof(HANDLE)); 290 | for (uintptr_t i = 0; i < nthreads; i++) { 291 | thandles[i] = CreateThread(0, 4096, &thread_entry, (void*)(i), 0, &tids[i]); 292 | } 293 | for (size_t i = 0; i < nthreads; i++) { 294 | WaitForSingleObject(thandles[i], INFINITE); 295 | } 296 | for (size_t i = 0; i < nthreads; i++) { 297 | CloseHandle(thandles[i]); 298 | } 299 | custom_free(tids); 300 | custom_free(thandles); 301 | } 302 | 303 | static void* atomic_exchange_ptr(volatile void** p, void* newval) { 304 | #if (INTPTR_MAX == INT32_MAX) 305 | return (void*)InterlockedExchange((volatile LONG*)p, (LONG)newval); 306 | #else 307 | return (void*)InterlockedExchange64((volatile LONG64*)p, (LONG64)newval); 308 | #endif 309 | } 310 | #else 311 | 312 | #include 313 | 314 | static void* thread_entry(void* param) { 315 | thread_entry_fun((uintptr_t)param); 316 | return NULL; 317 | } 318 | 319 | static void run_os_threads(size_t nthreads, void (*fun)(intptr_t)) { 320 | thread_entry_fun = fun; 321 | pthread_t* threads = (pthread_t*)custom_calloc(nthreads,sizeof(pthread_t)); 322 | memset(threads, 0, sizeof(pthread_t) * nthreads); 323 | //pthread_setconcurrency(nthreads); 324 | for (uintptr_t i = 0; i < nthreads; i++) { 325 | pthread_create(&threads[i], NULL, &thread_entry, (void*)i); 326 | } 327 | for (size_t i = 0; i < nthreads; i++) { 328 | pthread_join(threads[i], NULL); 329 | } 330 | custom_free(threads); 331 | } 332 | 333 | #ifdef __cplusplus 334 | #include 335 | static void* atomic_exchange_ptr(volatile void** p, void* newval) { 336 | return std::atomic_exchange((volatile std::atomic*)p, newval); 337 | } 338 | #else 339 | #include 340 | static void* atomic_exchange_ptr(volatile void** p, void* newval) { 341 | return atomic_exchange((volatile _Atomic(void*)*)p, newval); 342 | } 343 | #endif 344 | 345 | #endif 346 | -------------------------------------------------------------------------------- /test/realloc.c: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | #include "../include/slimguard.h" 4 | #include "../include/slimguard-large.h" 5 | #include "../include/sll.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define OLD_SIZE 128 13 | #define NEW_SIZE 2048 14 | 15 | #if OLD_SIZE > NEW_SIZE 16 | #error "OLD_SIZE must be < NEW_SIZE" 17 | #endif 18 | 19 | TEST_CASE("realloc", "[slimguard]") { 20 | void *ptr = xxmalloc(OLD_SIZE); 21 | REQUIRE(ptr); 22 | memset(ptr, 0x0, OLD_SIZE); 23 | 24 | ptr = xxrealloc(ptr, NEW_SIZE); 25 | memset((char *)ptr + OLD_SIZE, 0x0, NEW_SIZE - OLD_SIZE); 26 | 27 | for(int i=0; ialign_size == (1<<20)); 20 | if(xxfree_large(p[i]) == -1){ 21 | printf("error %d %p\n", i, p[i]); 22 | } 23 | } 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /test/slimguard-test.c: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | #include "../include/slimguard.h" 4 | #include "../include/slimguard-large.h" 5 | #include "../include/sll.h" 6 | 7 | TEST_CASE("bitmap", "[slimguard]") 8 | { 9 | int num = 1000000; 10 | void *ptr[num]; 11 | 12 | for (int i = 0; i < num; i++) { 13 | int size = rand()%1024; 14 | ptr[i] = xxmalloc(size); 15 | REQUIRE(ptr[i]); 16 | memset(ptr[i], 0x0, size); 17 | } 18 | 19 | for (int i = (num-1); i >= 0; i--) { 20 | xxfree(ptr[i]); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/very-large.c: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include "catch.hpp" 3 | #include "../include/slimguard.h" 4 | #include "../include/slimguard-large.h" 5 | #include "../include/sll.h" 6 | 7 | #define MAX_ALIGNMENT (1024*1024) 8 | #define ITERATIONS 500 9 | #define VERBOSE 0 10 | 11 | void* p[256]; 12 | uintptr_t buf[256]; 13 | 14 | TEST_CASE("very_large", "[slimguard]") 15 | { 16 | p[0] = xxmalloc(-8); 17 | REQUIRE(!p[0]); 18 | fprintf(stderr, "%p\n", p[0]); 19 | } 20 | --------------------------------------------------------------------------------