/src/yara/libyara/notebook.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (c) 2020. The YARA Authors. All Rights Reserved. |
3 | | |
4 | | Redistribution and use in source and binary forms, with or without modification, |
5 | | are permitted provided that the following conditions are met: |
6 | | |
7 | | 1. Redistributions of source code must retain the above copyright notice, this |
8 | | list of conditions and the following disclaimer. |
9 | | |
10 | | 2. Redistributions in binary form must reproduce the above copyright notice, |
11 | | this list of conditions and the following disclaimer in the documentation and/or |
12 | | other materials provided with the distribution. |
13 | | |
14 | | 3. Neither the name of the copyright holder nor the names of its contributors |
15 | | may be used to endorse or promote products derived from this software without |
16 | | specific prior written permission. |
17 | | |
18 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
19 | | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
22 | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
25 | | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | |
30 | | #include <assert.h> |
31 | | #include <stdint.h> |
32 | | #include <yara/error.h> |
33 | | #include <yara/mem.h> |
34 | | #include <yara/notebook.h> |
35 | | |
36 | | // Forward declaration of YR_NOTEBOOK_PAGE. |
37 | | typedef struct YR_NOTEBOOK_PAGE YR_NOTEBOOK_PAGE; |
38 | | |
39 | | // A notebook is a data structure that can be used for allocating memory |
40 | | // space in the same way malloc() would do. However, the buffers returned |
41 | | // by yr_notebook_alloc() are backed by a larger buffer reserved by the notebook |
42 | | // beforehand called a "page". The notebook fulfills the allocations performed |
43 | | // via yr_notebook_alloc() with space taken from the current page, or creates |
44 | | // a new page when necessary. It's recommended that the page size is at least |
45 | | // 4x the size of the buffers you plan to allocate with yr_notebook_alloc(). |
46 | | // |
47 | | // Once the notebook is destroyed all the pages are freed, and consequently |
48 | | // all the buffers allocated via yr_notebook_alloc(). |
49 | | struct YR_NOTEBOOK |
50 | | { |
51 | | // The mininum size of each page in the notebook. |
52 | | size_t min_page_size; |
53 | | // Pointer to the first page in the book, this is also the most recently |
54 | | // created page, the one that is being filled. |
55 | | YR_NOTEBOOK_PAGE* page_list_head; |
56 | | }; |
57 | | |
58 | | struct YR_NOTEBOOK_PAGE |
59 | | { |
60 | | // Size of this page. |
61 | | size_t size; |
62 | | // Amount of bytes in the page that are actually used. |
63 | | size_t used; |
64 | | // Pointer to next page. |
65 | | YR_NOTEBOOK_PAGE* next; |
66 | | // Page's data. |
67 | | // |
68 | | // This field must be 8-byte aligned to guarantee that all notebooks |
69 | | // allocations are 8-byte aligned. |
70 | | YR_ALIGN(8) uint8_t data[0]; |
71 | | }; |
72 | | |
73 | | //////////////////////////////////////////////////////////////////////////////// |
74 | | // Creates a new notebook. The notebook initially has a single page of size |
75 | | // min_page_size, but more pages will be created as needed. |
76 | | // |
77 | | // Args: |
78 | | // min_page_size: The minimum size of each page in the notebook. |
79 | | // notebook: Address of a pointer to the newly created notebook. |
80 | | // |
81 | | // Returns: |
82 | | // ERROR_SUCCESS |
83 | | // ERROR_INSUFFICIENT_MEMORY |
84 | | // |
85 | | int yr_notebook_create(size_t min_page_size, YR_NOTEBOOK** notebook) |
86 | 0 | { |
87 | 0 | YR_NOTEBOOK* new_notebook = yr_malloc(sizeof(YR_NOTEBOOK)); |
88 | |
|
89 | 0 | if (new_notebook == NULL) |
90 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
91 | | |
92 | 0 | new_notebook->page_list_head = yr_malloc( |
93 | 0 | sizeof(YR_NOTEBOOK_PAGE) + min_page_size); |
94 | |
|
95 | 0 | if (new_notebook->page_list_head == NULL) |
96 | 0 | { |
97 | 0 | yr_free(new_notebook); |
98 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
99 | 0 | } |
100 | | |
101 | 0 | new_notebook->min_page_size = min_page_size; |
102 | 0 | new_notebook->page_list_head->size = min_page_size; |
103 | 0 | new_notebook->page_list_head->used = 0; |
104 | 0 | new_notebook->page_list_head->next = NULL; |
105 | |
|
106 | 0 | *notebook = new_notebook; |
107 | |
|
108 | 0 | return ERROR_SUCCESS; |
109 | 0 | } |
110 | | |
111 | | //////////////////////////////////////////////////////////////////////////////// |
112 | | // Destroys a notebook and frees all the notebook's pages. |
113 | | // |
114 | | // Args: |
115 | | // notebook: Pointer to the notebook being destroyed. |
116 | | // |
117 | | // Returns: |
118 | | // ERROR_SUCCESS |
119 | | // |
120 | | int yr_notebook_destroy(YR_NOTEBOOK* notebook) |
121 | 0 | { |
122 | 0 | YR_NOTEBOOK_PAGE* page = notebook->page_list_head; |
123 | |
|
124 | 0 | while (page != NULL) |
125 | 0 | { |
126 | 0 | YR_NOTEBOOK_PAGE* next = page->next; |
127 | 0 | yr_free(page); |
128 | 0 | page = next; |
129 | 0 | } |
130 | |
|
131 | 0 | yr_free(notebook); |
132 | |
|
133 | 0 | return ERROR_SUCCESS; |
134 | 0 | } |
135 | | |
136 | | //////////////////////////////////////////////////////////////////////////////// |
137 | | // Allocates a memory buffer from a notebook. The memory is freed when the |
138 | | // notebook is destroyed, allocated buffers can't be freed individually. The |
139 | | // returned buffer is guaranteed to be aligned to an 8-byte boundary. |
140 | | // |
141 | | // Args: |
142 | | // notebook: Pointer to the notebook. |
143 | | // size: Size of the allocated memory. |
144 | | // |
145 | | // Returns: |
146 | | // Pointer to the allocated memory, or NULL if the allocation fails. |
147 | | // |
148 | | void* yr_notebook_alloc(YR_NOTEBOOK* notebook, size_t size) |
149 | 0 | { |
150 | | // Round up the size to a multiple of 8, which also implies that the returned |
151 | | // pointers are aligned to 8 bytes. The 8-byte alignment is required by some |
152 | | // platforms (e.g. ARM and Sparc) that have strict alignment requirements when |
153 | | // deferrencing pointers to types larger than a byte. |
154 | 0 | size = (size + 7) & ~0x7; |
155 | |
|
156 | 0 | YR_NOTEBOOK_PAGE* current_page = notebook->page_list_head; |
157 | | |
158 | | // If the requested size doesn't fit in current page's free space, allocate |
159 | | // a new page. |
160 | 0 | if (current_page->size - current_page->used < size) |
161 | 0 | { |
162 | 0 | size_t min_size = notebook->min_page_size; |
163 | | |
164 | | // The new page must be able to fit the requested buffer, so find the |
165 | | // multiple of notebook->min_page_size that is larger or equal than than |
166 | | // size. |
167 | 0 | size_t page_size = (size / min_size) * min_size + min_size; |
168 | |
|
169 | 0 | YR_NOTEBOOK_PAGE* new_page = yr_malloc( |
170 | 0 | sizeof(YR_NOTEBOOK_PAGE) + page_size); |
171 | |
|
172 | 0 | if (new_page == NULL) |
173 | 0 | return NULL; |
174 | | |
175 | 0 | new_page->size = page_size; |
176 | 0 | new_page->used = 0; |
177 | 0 | new_page->next = notebook->page_list_head; |
178 | 0 | notebook->page_list_head = new_page; |
179 | 0 | } |
180 | | |
181 | 0 | void* ptr = notebook->page_list_head->data + notebook->page_list_head->used; |
182 | |
|
183 | 0 | notebook->page_list_head->used += size; |
184 | |
|
185 | 0 | return ptr; |
186 | 0 | } |