Coverage Report

Created: 2026-09-14 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httrack/src/htsarena.h
Line
Count
Source
1
/* ------------------------------------------------------------ */
2
/*
3
HTTrack Website Copier, Offline Browser for Windows and Unix
4
Copyright (C) 1998 Xavier Roche and other contributors
5
6
SPDX-License-Identifier: GPL-3.0-or-later
7
8
This program is free software: you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation, either version 3 of the License, or
11
(at your option) any later version.
12
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21
Please visit our Website: http://www.httrack.com
22
*/
23
24
/* ------------------------------------------------------------ */
25
/* File: htsarena.h bump allocator whose allocations never move  */
26
/* Author: Xavier Roche                                         */
27
/* ------------------------------------------------------------ */
28
29
#ifndef HTSARENA_DEFH
30
#define HTSARENA_DEFH
31
32
#include "htsglobal.h"
33
#include "htssafe.h"
34
35
#include <string.h>
36
37
/** @file htsarena.h
38
 *  Bump allocator over chunks that are never resized, so what it hands out
39
 *  keeps its address, which the realloc-based String and TypedArray cannot
40
 *  promise. Nothing is released until the whole arena is. **/
41
42
/** Alignment fit for anything an arena is asked to hold. **/
43
typedef union {
44
  void *p;
45
  long l;
46
  double d;
47
} hts_arena_align;
48
49
typedef struct hts_arena_chunk hts_arena_chunk;
50
51
struct hts_arena_chunk {
52
  hts_arena_chunk *next;
53
};
54
55
typedef struct {
56
  hts_arena_chunk *chunks; /* newest first; allocations are cut from it */
57
  size_t size;             /* the newest chunk, used of size bytes taken */
58
  size_t used;
59
} hts_arena;
60
61
0
#define HTS_ARENA_ALIGN sizeof(hts_arena_align)
62
63
/** Smallest chunk, then doubling up to the largest. **/
64
0
#define HTS_ARENA_MIN 32768
65
0
#define HTS_ARENA_MAX (16 * 1024 * 1024)
66
67
/** The padding below assumes a power of two, and a header that is already a
68
    multiple of it; neither can change without this failing to compile. **/
69
HTS_STATIC_ASSERT(!(HTS_ARENA_ALIGN & (HTS_ARENA_ALIGN - 1)), arena_align_pow2);
70
71
/** First aligned offset past the chunk header, where its bytes begin. **/
72
#define HTS_ARENA_HDR                                                          \
73
0
  ((sizeof(hts_arena_chunk) + HTS_ARENA_ALIGN - 1) &                           \
74
0
   ~(size_t) (HTS_ARENA_ALIGN - 1))
75
76
/** Take a chunk with room for NEED bytes; ARENA is unchanged on failure. **/
77
0
static HTS_UNUSED hts_boolean hts_arena_grow_(hts_arena *arena, size_t need) {
78
0
  size_t size = arena->size < HTS_ARENA_MAX / 2 ? arena->size * 2
79
0
                                                : (size_t) HTS_ARENA_MAX;
80
0
  hts_arena_chunk *chunk;
81
82
0
  if (size < HTS_ARENA_MIN)
83
0
    size = HTS_ARENA_MIN;
84
0
  if (size < need)
85
0
    size = need;
86
0
  if (size > (size_t) -1 - HTS_ARENA_HDR)
87
0
    return HTS_FALSE;
88
0
  chunk = (hts_arena_chunk *) malloct(HTS_ARENA_HDR + size);
89
0
  if (chunk == NULL)
90
0
    return HTS_FALSE;
91
0
  chunk->next = arena->chunks;
92
0
  arena->chunks = chunk;
93
0
  arena->size = size;
94
0
  arena->used = 0;
95
0
  return HTS_TRUE;
96
0
}
97
98
HTS_STATIC_ASSERT(HTS_ARENA_HDR % HTS_ARENA_ALIGN == 0, arena_hdr_aligned);
99
100
/** SIZE bytes from ARENA, starting on an ALIGN boundary (a power of two), or
101
    NULL when out of memory. Padding is charged where it is needed rather than
102
    to every size, so a run of strings stays packed. **/
103
static HTS_UNUSED void *hts_arena_take_(hts_arena *arena, size_t size,
104
0
                                        size_t align) {
105
0
  if (arena->chunks != NULL) {
106
    /* used never passes size, so the room below can not go negative */
107
0
    const size_t room = arena->size - arena->used;
108
0
    const size_t pad = (align - (arena->used & (align - 1))) & (align - 1);
109
110
    /* pad, then size, each alone on one side: neither test can wrap */
111
0
    if (pad <= room && size <= room - pad) {
112
0
      char *const at =
113
0
          (char *) arena->chunks + HTS_ARENA_HDR + arena->used + pad;
114
115
0
      arena->used += pad + size;
116
0
      return at;
117
0
    }
118
0
  }
119
  /* a fresh chunk begins aligned, so it needs no padding */
120
0
  if (!hts_arena_grow_(arena, size))
121
0
    return NULL;
122
0
  arena->used = size;
123
0
  return (char *) arena->chunks + HTS_ARENA_HDR;
124
0
}
125
126
/** SIZE bytes from ARENA, aligned for any type, or NULL when out of memory.
127
    The address stays valid until hts_arena_free(). **/
128
0
static HTS_UNUSED void *hts_arena_alloc(hts_arena *arena, size_t size) {
129
0
  return hts_arena_take_(arena, size, HTS_ARENA_ALIGN);
130
0
}
131
132
/** A copy of S in ARENA, or NULL when out of memory. **/
133
0
static HTS_UNUSED char *hts_arena_strdup(hts_arena *arena, const char *s) {
134
0
  const size_t len = strlen(s) + 1;
135
0
  char *const copy = (char *) hts_arena_take_(arena, len, 1);
136
137
0
  if (copy != NULL)
138
0
    memcpy(copy, s, len);
139
0
  return copy;
140
0
}
141
142
/** Release every chunk, and with them everything the arena handed out. **/
143
0
static HTS_UNUSED void hts_arena_free(hts_arena *arena) {
144
0
  hts_arena_chunk *chunk = arena->chunks;
145
146
0
  while (chunk != NULL) {
147
0
    hts_arena_chunk *const next = chunk->next;
148
149
    freet(chunk);
150
0
    chunk = next;
151
0
  }
152
0
  memset(arena, 0, sizeof(*arena));
153
0
}
154
155
#endif