Coverage Report

Created: 2025-02-15 06:25

/src/wireshark/wsutil/buffer.c
Line
Count
Source (jump to first uncovered line)
1
/* buffer.c
2
 *
3
 * Wiretap Library
4
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5
 *
6
 * SPDX-License-Identifier: GPL-2.0-or-later
7
 */
8
#include "config.h"
9
0
#define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL
10
#include "buffer.h"
11
12
#include <stdlib.h>
13
#include <string.h>
14
15
#include <wsutil/ws_assert.h>
16
#include <wsutil/wslog.h>
17
18
623k
#define SMALL_BUFFER_SIZE (2 * 1024) /* Everyone still uses 1500 byte frames, right? */
19
static GPtrArray *small_buffers; /* Guaranteed to be at least SMALL_BUFFER_SIZE */
20
/* XXX - Add medium and large buffers? */
21
22
/* Initializes a buffer with a certain amount of allocated space */
23
void
24
ws_buffer_init(Buffer* buffer, size_t space)
25
207k
{
26
207k
  ws_assert(buffer);
27
207k
  if (G_UNLIKELY(!small_buffers)) small_buffers = g_ptr_array_sized_new(1024);
28
29
207k
  if (space <= SMALL_BUFFER_SIZE) {
30
207k
    if (small_buffers->len > 0) {
31
207k
      buffer->data = (uint8_t*) g_ptr_array_remove_index(small_buffers, small_buffers->len - 1);
32
207k
      ws_assert(buffer->data);
33
207k
    } else {
34
14
      buffer->data = (uint8_t*)g_malloc(SMALL_BUFFER_SIZE);
35
14
    }
36
207k
    buffer->allocated = SMALL_BUFFER_SIZE;
37
207k
  } else {
38
3
    buffer->data = (uint8_t*)g_malloc(space);
39
3
    buffer->allocated = space;
40
3
  }
41
207k
  buffer->start = 0;
42
207k
  buffer->first_free = 0;
43
207k
}
44
45
/* Frees the memory used by a buffer */
46
void
47
ws_buffer_free(Buffer* buffer)
48
207k
{
49
207k
  ws_assert(buffer);
50
207k
  if (buffer->allocated == SMALL_BUFFER_SIZE) {
51
207k
    ws_assert(buffer->data);
52
207k
    g_ptr_array_add(small_buffers, buffer->data);
53
207k
  } else {
54
3
    g_free(buffer->data);
55
3
  }
56
207k
  buffer->allocated = 0;
57
207k
  buffer->data = NULL;
58
207k
}
59
60
/* Assures that there are 'space' bytes at the end of the used space
61
  so that another routine can copy directly into the buffer space. After
62
  doing that, the routine will also want to run
63
  ws_buffer_increase_length(). */
64
void
65
ws_buffer_assure_space(Buffer* buffer, size_t space)
66
103k
{
67
103k
  ws_assert(buffer);
68
103k
  size_t available_at_end = buffer->allocated - buffer->first_free;
69
103k
  size_t space_used;
70
103k
  bool space_at_beginning;
71
72
  /* If we've got the space already, good! */
73
103k
  if (space <= available_at_end) {
74
103k
    return;
75
103k
  }
76
77
  /* Maybe we don't have the space available at the end, but we would
78
    if we moved the used space back to the beginning of the
79
    allocation. The buffer could have become fragmented through lots
80
    of calls to ws_buffer_remove_start(). I'm using buffer->start as the
81
    same as 'available_at_start' in this comparison. */
82
83
  /* or maybe there's just no more room. */
84
85
0
  space_at_beginning = buffer->start >= space;
86
0
  if (space_at_beginning || buffer->start > 0) {
87
0
    space_used = buffer->first_free - buffer->start;
88
    /* this memory copy better be safe for overlapping memory regions! */
89
0
    memmove(buffer->data, buffer->data + buffer->start, space_used);
90
0
    buffer->start = 0;
91
0
    buffer->first_free = space_used;
92
0
  }
93
  /*if (buffer->start >= space) {*/
94
0
  if (space_at_beginning) {
95
0
    return;
96
0
  }
97
98
  /* We'll allocate more space */
99
0
  buffer->allocated += space + 1024;
100
0
  buffer->data = (uint8_t*)g_realloc(buffer->data, buffer->allocated);
101
0
}
102
103
void
104
ws_buffer_append(Buffer* buffer, const uint8_t *from, size_t bytes)
105
103k
{
106
103k
  ws_assert(buffer);
107
103k
  ws_buffer_assure_space(buffer, bytes);
108
103k
  memcpy(buffer->data + buffer->first_free, from, bytes);
109
103k
  buffer->first_free += bytes;
110
103k
}
111
112
void
113
ws_buffer_remove_start(Buffer* buffer, size_t bytes)
114
0
{
115
0
  ws_assert(buffer);
116
0
  if (buffer->start + bytes > buffer->first_free) {
117
0
    ws_error("ws_buffer_remove_start trying to remove %" PRIu64 " bytes. s=%" PRIu64 " ff=%" PRIu64 "!\n",
118
0
      (uint64_t)bytes, (uint64_t)buffer->start,
119
0
      (uint64_t)buffer->first_free);
120
    /** ws_error() does an abort() and thus never returns **/
121
0
  }
122
0
  buffer->start += bytes;
123
124
  /*
125
   * If we've removed everything in the buffer, just reset
126
   * the buffer.
127
   */
128
0
  if (buffer->start == buffer->first_free)
129
0
    ws_buffer_clean(buffer);
130
0
}
131
132
133
#ifndef SOME_FUNCTIONS_ARE_INLINE
134
void
135
ws_buffer_clean(Buffer* buffer)
136
{
137
  ws_assert(buffer);
138
  buffer->start = 0;
139
  buffer->first_free = 0;
140
}
141
142
void
143
ws_buffer_increase_length(Buffer* buffer, size_t bytes)
144
{
145
  ws_assert(buffer);
146
  buffer->first_free += bytes;
147
}
148
149
size_t
150
ws_buffer_length(const Buffer* buffer)
151
{
152
  ws_assert(buffer);
153
  return buffer->first_free - buffer->start;
154
}
155
156
uint8_t *
157
ws_buffer_start_ptr(const Buffer* buffer)
158
{
159
  ws_assert(buffer);
160
  return buffer->data + buffer->start;
161
}
162
163
uint8_t *
164
ws_buffer_end_ptr(const Buffer* buffer)
165
{
166
  ws_assert(buffer);
167
  return buffer->data + buffer->first_free;
168
}
169
170
void
171
ws_buffer_append_buffer(Buffer* buffer, Buffer* src_buffer)
172
{
173
  ws_assert(buffer);
174
  ws_buffer_append(buffer, ws_buffer_start_ptr(src_buffer), ws_buffer_length(src_buffer));
175
}
176
#endif
177
178
void
179
ws_buffer_cleanup(void)
180
0
{
181
0
  if (small_buffers) {
182
0
    g_ptr_array_set_free_func(small_buffers, g_free);
183
0
    g_ptr_array_free(small_buffers, true);
184
0
    small_buffers = NULL;
185
0
  }
186
0
}
187
188
/*
189
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
190
 *
191
 * Local variables:
192
 * c-basic-offset: 8
193
 * tab-width: 8
194
 * indent-tabs-mode: t
195
 * End:
196
 *
197
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
198
 * :indentSize=8:tabSize=8:noTabs=false:
199
 */