/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 | | // Size of each page in the notebook. |
52 | | size_t 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 | | // Amount of bytes in the page that are actually used. |
61 | | size_t used; |
62 | | // Pointer to next page. |
63 | | YR_NOTEBOOK_PAGE* next; |
64 | | // Page's data. |
65 | | uint8_t data[0]; |
66 | | }; |
67 | | |
68 | | //////////////////////////////////////////////////////////////////////////////// |
69 | | // Creates a new notebook. The notebook initially has a single page of the |
70 | | // specified size, but more pages are created if needed. |
71 | | // |
72 | | // Args: |
73 | | // page_size: Size of each page in the notebook. |
74 | | // notebook: Address of a pointer to the newly created notebook. |
75 | | // |
76 | | // Returns: |
77 | | // ERROR_SUCCESS |
78 | | // ERROR_INSUFFICIENT_MEMORY |
79 | | // |
80 | | int yr_notebook_create(size_t page_size, YR_NOTEBOOK** notebook) |
81 | 6.13k | { |
82 | 6.13k | YR_NOTEBOOK* new_notebook = yr_malloc(sizeof(YR_NOTEBOOK)); |
83 | | |
84 | 6.13k | if (new_notebook == NULL) |
85 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
86 | | |
87 | 6.13k | new_notebook->page_list_head = yr_malloc( |
88 | 6.13k | sizeof(YR_NOTEBOOK_PAGE) + page_size); |
89 | | |
90 | 6.13k | if (new_notebook->page_list_head == NULL) |
91 | 0 | { |
92 | 0 | yr_free(new_notebook); |
93 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
94 | 0 | } |
95 | | |
96 | 6.13k | new_notebook->page_size = page_size; |
97 | 6.13k | new_notebook->page_list_head->used = 0; |
98 | 6.13k | new_notebook->page_list_head->next = NULL; |
99 | | |
100 | 6.13k | *notebook = new_notebook; |
101 | | |
102 | 6.13k | return ERROR_SUCCESS; |
103 | 6.13k | } |
104 | | |
105 | | //////////////////////////////////////////////////////////////////////////////// |
106 | | // Destroys a notebook and frees all the notebook's pages. |
107 | | // |
108 | | // Args: |
109 | | // notebook: Pointer to the notebook being destroyed. |
110 | | // |
111 | | // Returns: |
112 | | // ERROR_SUCCESS |
113 | | // |
114 | | int yr_notebook_destroy(YR_NOTEBOOK* notebook) |
115 | 6.13k | { |
116 | 6.13k | YR_NOTEBOOK_PAGE* page = notebook->page_list_head; |
117 | | |
118 | 12.2k | while (page != NULL) |
119 | 6.13k | { |
120 | 6.13k | YR_NOTEBOOK_PAGE* next = page->next; |
121 | 6.13k | yr_free(page); |
122 | 6.13k | page = next; |
123 | 6.13k | } |
124 | | |
125 | 6.13k | yr_free(notebook); |
126 | | |
127 | 6.13k | return ERROR_SUCCESS; |
128 | 6.13k | } |
129 | | |
130 | | //////////////////////////////////////////////////////////////////////////////// |
131 | | // Allocates a memory buffer from a notebook. The memory is freed when the |
132 | | // notebook is destroyed, allocated buffers can't be freed individually. The |
133 | | // returned buffer is guaranteed to be aligned to an 8-byte boundary. |
134 | | // |
135 | | // Args: |
136 | | // notebook: Pointer to the notebook. |
137 | | // size: Size of the allocated memory. |
138 | | // |
139 | | // Returns: |
140 | | // Pointer to the allocated memory, or NULL if the allocation fails. |
141 | | // |
142 | | void* yr_notebook_alloc(YR_NOTEBOOK* notebook, size_t size) |
143 | 0 | { |
144 | | // Round up the size to a multiple of 8, which also implies that the returned |
145 | | // pointers are aligned to 8 bytes. The 8-byte alignment is required by some |
146 | | // platforms (e.g. ARM and Sparc) that have strict alignment requirements when |
147 | | // deferrencing pointers to types larger than a byte. |
148 | 0 | size = (size + 7) & ~0x7; |
149 | | |
150 | | // The requested memory size can't be larger than a notebook's page. |
151 | 0 | assert(size <= notebook->page_size); |
152 | | |
153 | | // If the requested size doesn't fit in current page's free space, allocate |
154 | | // a new page. |
155 | 0 | if (notebook->page_size - notebook->page_list_head->used < size) |
156 | 0 | { |
157 | 0 | YR_NOTEBOOK_PAGE* new_page = yr_malloc( |
158 | 0 | sizeof(YR_NOTEBOOK_PAGE) + notebook->page_size); |
159 | |
|
160 | 0 | if (new_page == NULL) |
161 | 0 | return NULL; |
162 | | |
163 | 0 | new_page->used = 0; |
164 | 0 | new_page->next = notebook->page_list_head; |
165 | 0 | notebook->page_list_head = new_page; |
166 | 0 | } |
167 | | |
168 | 0 | void* ptr = notebook->page_list_head->data + notebook->page_list_head->used; |
169 | |
|
170 | 0 | notebook->page_list_head->used += size; |
171 | |
|
172 | 0 | return ptr; |
173 | 0 | } |