Coverage Report

Created: 2025-07-02 06:55

/src/openssh/bitmap.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD: bitmap.c,v 1.9 2017/10/20 01:56:39 djm Exp $ */
2
/*
3
 * Copyright (c) 2015 Damien Miller <djm@mindrot.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
#include "includes.h"
19
20
#include <sys/types.h>
21
#include <string.h>
22
#include <stdlib.h>
23
24
#include "bitmap.h"
25
26
0
#define BITMAP_WTYPE  u_int
27
0
#define BITMAP_MAX  (1<<24)
28
0
#define BITMAP_BYTES  (sizeof(BITMAP_WTYPE))
29
0
#define BITMAP_BITS (sizeof(BITMAP_WTYPE) * 8)
30
0
#define BITMAP_WMASK  ((BITMAP_WTYPE)BITMAP_BITS - 1)
31
struct bitmap {
32
  BITMAP_WTYPE *d;
33
  size_t len; /* number of words allocated */
34
  size_t top; /* index of top word allocated */
35
};
36
37
struct bitmap *
38
bitmap_new(void)
39
0
{
40
0
  struct bitmap *ret;
41
42
0
  if ((ret = calloc(1, sizeof(*ret))) == NULL)
43
0
    return NULL;
44
0
  if ((ret->d = calloc(1, BITMAP_BYTES)) == NULL) {
45
0
    free(ret);
46
0
    return NULL;
47
0
  }
48
0
  ret->len = 1;
49
0
  ret->top = 0;
50
0
  return ret;
51
0
}
52
53
void
54
bitmap_free(struct bitmap *b)
55
0
{
56
0
  if (b != NULL && b->d != NULL) {
57
0
    bitmap_zero(b);
58
0
    free(b->d);
59
0
    b->d = NULL;
60
0
  }
61
0
  free(b);
62
0
}
63
64
void
65
bitmap_zero(struct bitmap *b)
66
0
{
67
0
  memset(b->d, 0, b->len * BITMAP_BYTES);
68
0
  b->top = 0;
69
0
}
70
71
int
72
bitmap_test_bit(struct bitmap *b, u_int n)
73
0
{
74
0
  if (b->top >= b->len)
75
0
    return 0; /* invalid */
76
0
  if (b->len == 0 || (n / BITMAP_BITS) > b->top)
77
0
    return 0;
78
0
  return (b->d[n / BITMAP_BITS] >> (n & BITMAP_WMASK)) & 1;
79
0
}
80
81
static int
82
reserve(struct bitmap *b, u_int n)
83
0
{
84
0
  BITMAP_WTYPE *tmp;
85
0
  size_t nlen;
86
87
0
  if (b->top >= b->len || n > BITMAP_MAX)
88
0
    return -1; /* invalid */
89
0
  nlen = (n / BITMAP_BITS) + 1;
90
0
  if (b->len < nlen) {
91
0
    if ((tmp = recallocarray(b->d, b->len,
92
0
        nlen, BITMAP_BYTES)) == NULL)
93
0
      return -1;
94
0
    b->d = tmp;
95
0
    b->len = nlen;
96
0
  }
97
0
  return 0;
98
0
}
99
100
int
101
bitmap_set_bit(struct bitmap *b, u_int n)
102
0
{
103
0
  int r;
104
0
  size_t offset;
105
106
0
  if ((r = reserve(b, n)) != 0)
107
0
    return r;
108
0
  offset = n / BITMAP_BITS;
109
0
  if (offset > b->top)
110
0
    b->top = offset;
111
0
  b->d[offset] |= (BITMAP_WTYPE)1 << (n & BITMAP_WMASK);
112
0
  return 0;
113
0
}
114
115
/* Resets b->top to point to the most significant bit set in b->d */
116
static void
117
retop(struct bitmap *b)
118
0
{
119
0
  if (b->top >= b->len)
120
0
    return;
121
0
  while (b->top > 0 && b->d[b->top] == 0)
122
0
    b->top--;
123
0
}
124
125
void
126
bitmap_clear_bit(struct bitmap *b, u_int n)
127
0
{
128
0
  size_t offset;
129
130
0
  if (b->top >= b->len || n > BITMAP_MAX)
131
0
    return; /* invalid */
132
0
  offset = n / BITMAP_BITS;
133
0
  if (offset > b->top)
134
0
    return;
135
0
  b->d[offset] &= ~((BITMAP_WTYPE)1 << (n & BITMAP_WMASK));
136
  /* The top may have changed as a result of the clear */
137
0
  retop(b);
138
0
}
139
140
size_t
141
bitmap_nbits(struct bitmap *b)
142
0
{
143
0
  size_t bits;
144
0
  BITMAP_WTYPE w;
145
146
0
  retop(b);
147
0
  if (b->top >= b->len)
148
0
    return 0; /* invalid */
149
0
  if (b->len == 0 || (b->top == 0 && b->d[0] == 0))
150
0
    return 0;
151
  /* Find MSB set */
152
0
  w = b->d[b->top];
153
0
  bits = (b->top + 1) * BITMAP_BITS;
154
0
  while (!(w & ((BITMAP_WTYPE)1 << (BITMAP_BITS - 1)))) {
155
0
    w <<= 1;
156
0
    bits--;
157
0
  }
158
0
  return bits;
159
0
}
160
161
size_t
162
bitmap_nbytes(struct bitmap *b)
163
0
{
164
0
  return (bitmap_nbits(b) + 7) / 8;
165
0
}
166
167
int
168
bitmap_to_string(struct bitmap *b, void *p, size_t l)
169
0
{
170
0
  u_char *s = (u_char *)p;
171
0
  size_t i, j, k, need = bitmap_nbytes(b);
172
173
0
  if (l < need || b->top >= b->len)
174
0
    return -1;
175
0
  if (l > need)
176
0
    l = need;
177
  /* Put the bytes from LSB backwards */
178
0
  for (i = k = 0; i < b->top + 1; i++) {
179
0
    for (j = 0; j < BITMAP_BYTES; j++) {
180
0
      if (k >= l)
181
0
        break;
182
0
      s[need - 1 - k++] = (b->d[i] >> (j * 8)) & 0xff;
183
0
    }
184
0
  }
185
0
  return 0;
186
0
}
187
188
int
189
bitmap_from_string(struct bitmap *b, const void *p, size_t l)
190
0
{
191
0
  int r;
192
0
  size_t i, offset, shift;
193
0
  const u_char *s = (const u_char *)p;
194
195
0
  if (l > BITMAP_MAX / 8)
196
0
    return -1;
197
0
  if ((r = reserve(b, l * 8)) != 0)
198
0
    return r;
199
0
  bitmap_zero(b);
200
0
  if (l == 0)
201
0
    return 0;
202
0
  b->top = offset = ((l + (BITMAP_BYTES - 1)) / BITMAP_BYTES) - 1;
203
0
  shift = ((l + (BITMAP_BYTES - 1)) % BITMAP_BYTES) * 8;
204
0
  for (i = 0; i < l; i++) {
205
0
    b->d[offset] |= (BITMAP_WTYPE)s[i] << shift;
206
0
    if (shift == 0) {
207
0
      offset--;
208
0
      shift = BITMAP_BITS - 8;
209
0
    } else
210
0
      shift -= 8;
211
0
  }
212
0
  retop(b);
213
0
  return 0;
214
0
}