Coverage Report

Created: 2023-09-25 07:13

/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
}