/src/yara/libyara/notebook.c
Line  | Count  | Source  | 
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  | 7.95k  | { | 
87  | 7.95k  |   YR_NOTEBOOK* new_notebook = yr_malloc(sizeof(YR_NOTEBOOK));  | 
88  |  |  | 
89  | 7.95k  |   if (new_notebook == NULL)  | 
90  | 0  |     return ERROR_INSUFFICIENT_MEMORY;  | 
91  |  |  | 
92  | 7.95k  |   new_notebook->page_list_head = yr_malloc(  | 
93  | 7.95k  |       sizeof(YR_NOTEBOOK_PAGE) + min_page_size);  | 
94  |  |  | 
95  | 7.95k  |   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  | 7.95k  |   new_notebook->min_page_size = min_page_size;  | 
102  | 7.95k  |   new_notebook->page_list_head->size = min_page_size;  | 
103  | 7.95k  |   new_notebook->page_list_head->used = 0;  | 
104  | 7.95k  |   new_notebook->page_list_head->next = NULL;  | 
105  |  |  | 
106  | 7.95k  |   *notebook = new_notebook;  | 
107  |  |  | 
108  | 7.95k  |   return ERROR_SUCCESS;  | 
109  | 7.95k  | }  | 
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  | 7.95k  | { | 
122  | 7.95k  |   YR_NOTEBOOK_PAGE* page = notebook->page_list_head;  | 
123  |  |  | 
124  | 15.9k  |   while (page != NULL)  | 
125  | 7.95k  |   { | 
126  | 7.95k  |     YR_NOTEBOOK_PAGE* next = page->next;  | 
127  | 7.95k  |     yr_free(page);  | 
128  | 7.95k  |     page = next;  | 
129  | 7.95k  |   }  | 
130  |  |  | 
131  | 7.95k  |   yr_free(notebook);  | 
132  |  |  | 
133  | 7.95k  |   return ERROR_SUCCESS;  | 
134  | 7.95k  | }  | 
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  | }  |