Coverage Report

Created: 2026-03-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/u-boot/lib/lz4_wrapper.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL 2.0+ OR BSD-3-Clause
2
/*
3
 * Copyright 2015 Google Inc.
4
 */
5
6
#include <compiler.h>
7
#include <image.h>
8
#include <linux/kernel.h>
9
#include <linux/types.h>
10
#include <asm/unaligned.h>
11
#include <u-boot/lz4.h>
12
13
/* lz4.c is unaltered (except removing unrelated code) from github.com/Cyan4973/lz4. */
14
#include "lz4.c"  /* #include for inlining, do not link! */
15
16
0
#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
17
18
__rcode int ulz4fn(const void *src, size_t srcn, void *dst, size_t *dstn)
19
0
{
20
0
  const void *end = dst + *dstn;
21
0
  const void *in = src;
22
0
  void *out = dst;
23
0
  int has_block_checksum;
24
0
  int ret;
25
0
  *dstn = 0;
26
27
0
  { /* With in-place decompression the header may become invalid later. */
28
0
    u32 magic;
29
0
    u8 flags, version, independent_blocks, has_content_size;
30
0
    u8 block_desc;
31
32
0
    if (srcn < sizeof(u32) + 3*sizeof(u8))
33
0
      return -EINVAL; /* input overrun */
34
35
0
    magic = get_unaligned_le32(in);
36
0
    in += sizeof(u32);
37
0
    flags = *(u8 *)in;
38
0
    in += sizeof(u8);
39
0
    block_desc = *(u8 *)in;
40
0
    in += sizeof(u8);
41
42
0
    version = (flags >> 6) & 0x3;
43
0
    independent_blocks = (flags >> 5) & 0x1;
44
0
    has_block_checksum = (flags >> 4) & 0x1;
45
0
    has_content_size = (flags >> 3) & 0x1;
46
47
    /* We assume there's always only a single, standard frame. */
48
0
    if (magic != LZ4F_MAGIC || version != 1)
49
0
      return -EPROTONOSUPPORT; /* unknown format */
50
0
    if ((flags & 0x03) || (block_desc & 0x8f))
51
0
      return -EINVAL; /* reserved bits must be zero */
52
0
    if (!independent_blocks)
53
0
      return -EPROTONOSUPPORT; /* we can't support this yet */
54
55
0
    if (has_content_size) {
56
0
      if (srcn < sizeof(u32) + 3*sizeof(u8) + sizeof(u64))
57
0
        return -EINVAL; /* input overrun */
58
0
      in += sizeof(u64);
59
0
    }
60
    /* Header checksum byte */
61
0
    in += sizeof(u8);
62
0
  }
63
64
0
  while (1) {
65
0
    u32 block_header, block_size;
66
67
0
    block_header = get_unaligned_le32(in);
68
0
    in += sizeof(u32);
69
0
    block_size = block_header & ~LZ4F_BLOCKUNCOMPRESSED_FLAG;
70
71
0
    if (in - src + block_size > srcn) {
72
0
      ret = -EINVAL;   /* input overrun */
73
0
      break;
74
0
    }
75
76
0
    if (!block_size) {
77
0
      ret = 0;  /* decompression successful */
78
0
      break;
79
0
    }
80
81
0
    if (block_header & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
82
0
      size_t size = min((ptrdiff_t)block_size, (ptrdiff_t)(end - out));
83
0
      memcpy(out, in, size);
84
0
      out += size;
85
0
      if (size < block_size) {
86
0
        ret = -ENOBUFS; /* output overrun */
87
0
        break;
88
0
      }
89
0
    } else {
90
      /* constant folding essential, do not touch params! */
91
0
      ret = LZ4_decompress_generic(in, out, block_size,
92
0
          end - out, endOnInputSize,
93
0
          decode_full_block, noDict, out, NULL, 0);
94
0
      if (ret < 0) {
95
0
        ret = -EPROTO; /* decompression error */
96
0
        break;
97
0
      }
98
0
      out += ret;
99
0
    }
100
101
0
    in += block_size;
102
0
    if (has_block_checksum)
103
0
      in += sizeof(u32);
104
0
  }
105
106
0
  *dstn = out - dst;
107
0
  return ret;
108
0
}