Coverage Report

Created: 2026-05-24 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xz/src/liblzma/common/common.c
Line
Count
Source
1
// SPDX-License-Identifier: 0BSD
2
3
///////////////////////////////////////////////////////////////////////////////
4
//
5
/// \file       common.c
6
/// \brief      Common functions needed in many places in liblzma
7
//
8
//  Author:     Lasse Collin
9
//
10
///////////////////////////////////////////////////////////////////////////////
11
12
#include "common.h"
13
14
15
/////////////
16
// Version //
17
/////////////
18
19
extern LZMA_API(uint32_t)
20
lzma_version_number(void)
21
0
{
22
0
  return LZMA_VERSION;
23
0
}
24
25
26
extern LZMA_API(const char *)
27
lzma_version_string(void)
28
0
{
29
0
  return LZMA_VERSION_STRING;
30
0
}
31
32
33
///////////////////////
34
// Memory allocation //
35
///////////////////////
36
37
lzma_attr_alloc_size(1)
38
extern void *
39
lzma_alloc(size_t size, const lzma_allocator *allocator)
40
165
{
41
  // Some malloc() variants return NULL if called with size == 0.
42
165
  if (size == 0)
43
0
    size = 1;
44
45
165
  void *ptr;
46
47
165
  if (allocator != NULL && allocator->alloc != NULL)
48
0
    ptr = allocator->alloc(allocator->opaque, 1, size);
49
165
  else
50
165
    ptr = malloc(size);
51
52
165
  return ptr;
53
165
}
54
55
56
lzma_attr_alloc_size(1)
57
extern void *
58
lzma_alloc_zero(size_t size, const lzma_allocator *allocator)
59
0
{
60
  // Some calloc() variants return NULL if called with size == 0.
61
0
  if (size == 0)
62
0
    size = 1;
63
64
0
  void *ptr;
65
66
0
  if (allocator != NULL && allocator->alloc != NULL) {
67
0
    ptr = allocator->alloc(allocator->opaque, 1, size);
68
0
    if (ptr != NULL)
69
0
      memzero(ptr, size);
70
0
  } else {
71
0
    ptr = calloc(1, size);
72
0
  }
73
74
0
  return ptr;
75
0
}
76
77
78
extern void
79
lzma_free(void *ptr, const lzma_allocator *allocator)
80
192
{
81
192
  if (allocator != NULL && allocator->free != NULL)
82
0
    allocator->free(allocator->opaque, ptr);
83
192
  else
84
192
    free(ptr);
85
86
192
  return;
87
192
}
88
89
90
//////////
91
// Misc //
92
//////////
93
94
extern size_t
95
lzma_bufcpy(const uint8_t *restrict in, size_t *restrict in_pos,
96
    size_t in_size, uint8_t *restrict out,
97
    size_t *restrict out_pos, size_t out_size)
98
92
{
99
92
  assert(in != NULL || *in_pos == in_size);
100
92
  assert(out != NULL || *out_pos == out_size);
101
102
92
  assert(*in_pos <= in_size);
103
92
  assert(*out_pos <= out_size);
104
105
92
  const size_t in_avail = in_size - *in_pos;
106
92
  const size_t out_avail = out_size - *out_pos;
107
92
  const size_t copy_size = my_min(in_avail, out_avail);
108
109
  // Call memcpy() only if there is something to copy. If there is
110
  // nothing to copy, in or out might be NULL and then the memcpy()
111
  // call would trigger undefined behavior.
112
92
  if (copy_size > 0)
113
86
    memcpy(out + *out_pos, in + *in_pos, copy_size);
114
115
92
  *in_pos += copy_size;
116
92
  *out_pos += copy_size;
117
118
92
  return copy_size;
119
92
}
120
121
122
extern lzma_ret
123
lzma_next_filter_init(lzma_next_coder *next, const lzma_allocator *allocator,
124
    const lzma_filter_info *filters)
125
0
{
126
0
  lzma_next_coder_init(filters[0].init, next, allocator);
127
0
  next->id = filters[0].id;
128
0
  return filters[0].init == NULL
129
0
      ? LZMA_OK : filters[0].init(next, allocator, filters);
130
0
}
131
132
133
extern lzma_ret
134
lzma_next_filter_update(lzma_next_coder *next, const lzma_allocator *allocator,
135
    const lzma_filter *reversed_filters)
136
0
{
137
  // Check that the application isn't trying to change the Filter ID.
138
  // End of filters is indicated with LZMA_VLI_UNKNOWN in both
139
  // reversed_filters[0].id and next->id.
140
0
  if (reversed_filters[0].id != next->id)
141
0
    return LZMA_PROG_ERROR;
142
143
0
  if (reversed_filters[0].id == LZMA_VLI_UNKNOWN)
144
0
    return LZMA_OK;
145
146
0
  assert(next->update != NULL);
147
0
  return next->update(next->coder, allocator, NULL, reversed_filters);
148
0
}
149
150
151
extern void
152
lzma_next_end(lzma_next_coder *next, const lzma_allocator *allocator)
153
156
{
154
156
  if (next->init != (uintptr_t)(NULL)) {
155
    // To avoid tiny end functions that simply call
156
    // lzma_free(coder, allocator), we allow leaving next->end
157
    // NULL and call lzma_free() here.
158
52
    if (next->end != NULL)
159
52
      next->end(next->coder, allocator);
160
0
    else
161
0
      lzma_free(next->coder, allocator);
162
163
    // Reset the variables so the we don't accidentally think
164
    // that it is an already initialized coder.
165
52
    *next = LZMA_NEXT_CODER_INIT;
166
52
  }
167
168
156
  return;
169
156
}
170
171
172
//////////////////////////////////////
173
// External to internal API wrapper //
174
//////////////////////////////////////
175
176
extern lzma_ret
177
lzma_strm_init(lzma_stream *strm)
178
52
{
179
52
  if (strm == NULL)
180
0
    return LZMA_PROG_ERROR;
181
182
52
  if (strm->internal == NULL) {
183
52
    strm->internal = lzma_alloc(sizeof(lzma_internal),
184
52
        strm->allocator);
185
52
    if (strm->internal == NULL)
186
0
      return LZMA_MEM_ERROR;
187
188
52
    strm->internal->next = LZMA_NEXT_CODER_INIT;
189
52
  }
190
191
52
  memzero(strm->internal->supported_actions,
192
52
      sizeof(strm->internal->supported_actions));
193
52
  strm->internal->sequence = ISEQ_RUN;
194
52
  strm->internal->allow_buf_error = false;
195
196
52
  strm->total_in = 0;
197
52
  strm->total_out = 0;
198
199
52
  return LZMA_OK;
200
52
}
201
202
203
extern LZMA_API(lzma_ret)
204
lzma_code(lzma_stream *strm, lzma_action action)
205
62
{
206
  // Sanity checks
207
62
  if ((strm->next_in == NULL && strm->avail_in != 0)
208
62
      || (strm->next_out == NULL && strm->avail_out != 0)
209
62
      || strm->internal == NULL
210
62
      || strm->internal->next.code == NULL
211
62
      || (unsigned int)(action) > LZMA_ACTION_MAX
212
62
      || !strm->internal->supported_actions[action])
213
0
    return LZMA_PROG_ERROR;
214
215
  // Check if unsupported members have been set to non-zero or non-NULL,
216
  // which would indicate that some new feature is wanted.
217
62
  if (strm->reserved_ptr1 != NULL
218
62
      || strm->reserved_ptr2 != NULL
219
62
      || strm->reserved_ptr3 != NULL
220
62
      || strm->reserved_ptr4 != NULL
221
62
      || strm->reserved_int2 != 0
222
62
      || strm->reserved_int3 != 0
223
62
      || strm->reserved_int4 != 0
224
62
      || strm->reserved_enum1 != LZMA_RESERVED_ENUM
225
62
      || strm->reserved_enum2 != LZMA_RESERVED_ENUM)
226
0
    return LZMA_OPTIONS_ERROR;
227
228
62
  switch (strm->internal->sequence) {
229
62
  case ISEQ_RUN:
230
62
    switch (action) {
231
62
    case LZMA_RUN:
232
62
      break;
233
234
0
    case LZMA_SYNC_FLUSH:
235
0
      strm->internal->sequence = ISEQ_SYNC_FLUSH;
236
0
      break;
237
238
0
    case LZMA_FULL_FLUSH:
239
0
      strm->internal->sequence = ISEQ_FULL_FLUSH;
240
0
      break;
241
242
0
    case LZMA_FINISH:
243
0
      strm->internal->sequence = ISEQ_FINISH;
244
0
      break;
245
246
0
    case LZMA_FULL_BARRIER:
247
0
      strm->internal->sequence = ISEQ_FULL_BARRIER;
248
0
      break;
249
62
    }
250
251
62
    break;
252
253
62
  case ISEQ_SYNC_FLUSH:
254
    // The same action must be used until we return
255
    // LZMA_STREAM_END, and the amount of input must not change.
256
0
    if (action != LZMA_SYNC_FLUSH
257
0
        || strm->internal->avail_in != strm->avail_in)
258
0
      return LZMA_PROG_ERROR;
259
260
0
    break;
261
262
0
  case ISEQ_FULL_FLUSH:
263
0
    if (action != LZMA_FULL_FLUSH
264
0
        || strm->internal->avail_in != strm->avail_in)
265
0
      return LZMA_PROG_ERROR;
266
267
0
    break;
268
269
0
  case ISEQ_FINISH:
270
0
    if (action != LZMA_FINISH
271
0
        || strm->internal->avail_in != strm->avail_in)
272
0
      return LZMA_PROG_ERROR;
273
274
0
    break;
275
276
0
  case ISEQ_FULL_BARRIER:
277
0
    if (action != LZMA_FULL_BARRIER
278
0
        || strm->internal->avail_in != strm->avail_in)
279
0
      return LZMA_PROG_ERROR;
280
281
0
    break;
282
283
0
  case ISEQ_END:
284
0
    return LZMA_STREAM_END;
285
286
0
  case ISEQ_ERROR:
287
0
  default:
288
0
    return LZMA_PROG_ERROR;
289
62
  }
290
291
62
  size_t in_pos = 0;
292
62
  size_t out_pos = 0;
293
62
  lzma_ret ret = strm->internal->next.code(
294
62
      strm->internal->next.coder, strm->allocator,
295
62
      strm->next_in, &in_pos, strm->avail_in,
296
62
      strm->next_out, &out_pos, strm->avail_out, action);
297
298
  // Updating next_in and next_out has to be skipped when they are NULL
299
  // to avoid null pointer + 0 (undefined behavior). Do this by checking
300
  // in_pos > 0 and out_pos > 0 because this way NULL + non-zero (a bug)
301
  // will get caught one way or other.
302
62
  if (in_pos > 0) {
303
52
    strm->next_in += in_pos;
304
52
    strm->avail_in -= in_pos;
305
52
    strm->total_in += in_pos;
306
52
  }
307
308
62
  if (out_pos > 0) {
309
0
    strm->next_out += out_pos;
310
0
    strm->avail_out -= out_pos;
311
0
    strm->total_out += out_pos;
312
0
  }
313
314
62
  strm->internal->avail_in = strm->avail_in;
315
316
62
  switch (ret) {
317
15
  case LZMA_OK:
318
    // Don't return LZMA_BUF_ERROR when it happens the first time.
319
    // This is to avoid returning LZMA_BUF_ERROR when avail_out
320
    // was zero but still there was no more data left to written
321
    // to next_out.
322
15
    if (out_pos == 0 && in_pos == 0) {
323
10
      if (strm->internal->allow_buf_error)
324
5
        ret = LZMA_BUF_ERROR;
325
5
      else
326
5
        strm->internal->allow_buf_error = true;
327
10
    } else {
328
5
      strm->internal->allow_buf_error = false;
329
5
    }
330
15
    break;
331
332
0
  case LZMA_TIMED_OUT:
333
0
    strm->internal->allow_buf_error = false;
334
0
    ret = LZMA_OK;
335
0
    break;
336
337
0
  case LZMA_SEEK_NEEDED:
338
0
    strm->internal->allow_buf_error = false;
339
340
    // If LZMA_FINISH was used, reset it back to the
341
    // LZMA_RUN-based state so that new input can be supplied
342
    // by the application.
343
0
    if (strm->internal->sequence == ISEQ_FINISH)
344
0
      strm->internal->sequence = ISEQ_RUN;
345
346
0
    break;
347
348
0
  case LZMA_STREAM_END:
349
0
    if (strm->internal->sequence == ISEQ_SYNC_FLUSH
350
0
        || strm->internal->sequence == ISEQ_FULL_FLUSH
351
0
        || strm->internal->sequence
352
0
          == ISEQ_FULL_BARRIER)
353
0
      strm->internal->sequence = ISEQ_RUN;
354
0
    else
355
0
      strm->internal->sequence = ISEQ_END;
356
357
0
    FALLTHROUGH;
358
359
0
  case LZMA_NO_CHECK:
360
0
  case LZMA_UNSUPPORTED_CHECK:
361
0
  case LZMA_GET_CHECK:
362
0
  case LZMA_MEMLIMIT_ERROR:
363
    // Something else than LZMA_OK, but not a fatal error,
364
    // that is, coding may be continued (except if ISEQ_END).
365
0
    strm->internal->allow_buf_error = false;
366
0
    break;
367
368
47
  default:
369
    // All the other errors are fatal; coding cannot be continued.
370
47
    assert(ret != LZMA_BUF_ERROR);
371
47
    strm->internal->sequence = ISEQ_ERROR;
372
47
    break;
373
62
  }
374
375
62
  return ret;
376
62
}
377
378
379
extern LZMA_API(void)
380
lzma_end(lzma_stream *strm)
381
55
{
382
55
  if (strm != NULL && strm->internal != NULL) {
383
52
    lzma_next_end(&strm->internal->next, strm->allocator);
384
52
    lzma_free(strm->internal, strm->allocator);
385
52
    strm->internal = NULL;
386
52
  }
387
388
55
  return;
389
55
}
390
391
392
#ifdef HAVE_SYMBOL_VERSIONS_LINUX
393
// This is for compatibility with binaries linked against liblzma that
394
// has been patched with xz-5.2.2-compat-libs.patch from RHEL/CentOS 7.
395
LZMA_SYMVER_API("lzma_get_progress@XZ_5.2.2",
396
  void, lzma_get_progress_522)(lzma_stream *strm,
397
    uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow
398
    __attribute__((__alias__("lzma_get_progress_52")));
399
400
LZMA_SYMVER_API("lzma_get_progress@@XZ_5.2",
401
  void, lzma_get_progress_52)(lzma_stream *strm,
402
    uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
403
404
#define lzma_get_progress lzma_get_progress_52
405
#endif
406
extern LZMA_API(void)
407
lzma_get_progress(lzma_stream *strm,
408
    uint64_t *progress_in, uint64_t *progress_out)
409
0
{
410
0
  if (strm->internal->next.get_progress != NULL) {
411
0
    strm->internal->next.get_progress(strm->internal->next.coder,
412
0
        progress_in, progress_out);
413
0
  } else {
414
0
    *progress_in = strm->total_in;
415
0
    *progress_out = strm->total_out;
416
0
  }
417
418
0
  return;
419
0
}
420
421
422
extern LZMA_API(lzma_check)
423
lzma_get_check(const lzma_stream *strm)
424
0
{
425
  // Return LZMA_CHECK_NONE if we cannot know the check type.
426
  // It's a bug in the application if this happens.
427
0
  if (strm->internal->next.get_check == NULL)
428
0
    return LZMA_CHECK_NONE;
429
430
0
  return strm->internal->next.get_check(strm->internal->next.coder);
431
0
}
432
433
434
extern LZMA_API(uint64_t)
435
lzma_memusage(const lzma_stream *strm)
436
0
{
437
0
  uint64_t memusage;
438
0
  uint64_t old_memlimit;
439
440
0
  if (strm == NULL || strm->internal == NULL
441
0
      || strm->internal->next.memconfig == NULL
442
0
      || strm->internal->next.memconfig(
443
0
        strm->internal->next.coder,
444
0
        &memusage, &old_memlimit, 0) != LZMA_OK)
445
0
    return 0;
446
447
0
  return memusage;
448
0
}
449
450
451
extern LZMA_API(uint64_t)
452
lzma_memlimit_get(const lzma_stream *strm)
453
0
{
454
0
  uint64_t old_memlimit;
455
0
  uint64_t memusage;
456
457
0
  if (strm == NULL || strm->internal == NULL
458
0
      || strm->internal->next.memconfig == NULL
459
0
      || strm->internal->next.memconfig(
460
0
        strm->internal->next.coder,
461
0
        &memusage, &old_memlimit, 0) != LZMA_OK)
462
0
    return 0;
463
464
0
  return old_memlimit;
465
0
}
466
467
468
extern LZMA_API(lzma_ret)
469
lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
470
0
{
471
  // Dummy variables to simplify memconfig functions
472
0
  uint64_t old_memlimit;
473
0
  uint64_t memusage;
474
475
0
  if (strm == NULL || strm->internal == NULL
476
0
      || strm->internal->next.memconfig == NULL)
477
0
    return LZMA_PROG_ERROR;
478
479
  // Zero is a special value that cannot be used as an actual limit.
480
  // If 0 was specified, use 1 instead.
481
0
  if (new_memlimit == 0)
482
0
    new_memlimit = 1;
483
484
0
  return strm->internal->next.memconfig(strm->internal->next.coder,
485
0
      &memusage, &old_memlimit, new_memlimit);
486
0
}