commonlib/lz4_wrapper.c: do not use bitfields

Order of bits in bitfields is implementation-defined. This makes them
non-portable, especially across systems using different endianness.

This change removes bitfields and uses masking and shifting instead.

Signed-off-by: Krystian Hebel <krystian.hebel@3mdeb.com>
Change-Id: Ief7d87ddb25c9baa931f27dbd54a4ca730b6ece7
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55040
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
Krystian Hebel 2020-10-08 19:19:42 +02:00 committed by Patrick Georgi
parent 926949d64c
commit 3c75a8db35
1 changed files with 33 additions and 39 deletions

View File

@ -63,39 +63,32 @@ typedef uint64_t U64;
#define LZ4F_MAGICNUMBER 0x184D2204 #define LZ4F_MAGICNUMBER 0x184D2204
/* Bit field endianness is implementation-defined. Use masks instead.
* https://stackoverflow.com/a/6044223 */
#define RESERVED0 0x03
#define HAS_CONTENT_CHECKSUM 0x04
#define HAS_CONTENT_SIZE 0x08
#define HAS_BLOCK_CHECKSUM 0x10
#define INDEPENDENT_BLOCKS 0x20
#define VERSION 0xC0
#define VERSION_SHIFT 6
#define RESERVED1_2 0x8F
#define MAX_BLOCK_SIZE 0x70
struct lz4_frame_header { struct lz4_frame_header {
uint32_t magic; uint32_t magic;
union {
uint8_t flags; uint8_t flags;
struct {
uint8_t reserved0 : 2;
uint8_t has_content_checksum : 1;
uint8_t has_content_size : 1;
uint8_t has_block_checksum : 1;
uint8_t independent_blocks : 1;
uint8_t version : 2;
};
};
union {
uint8_t block_descriptor; uint8_t block_descriptor;
struct {
uint8_t reserved1 : 4;
uint8_t max_block_size : 3;
uint8_t reserved2 : 1;
};
};
/* + uint64_t content_size iff has_content_size is set */ /* + uint64_t content_size iff has_content_size is set */
/* + uint8_t header_checksum */ /* + uint8_t header_checksum */
} __packed; } __packed;
#define BH_SIZE 0x7FFFFFFF
#define NOT_COMPRESSED 0x80000000
struct lz4_block_header { struct lz4_block_header {
union {
uint32_t raw; uint32_t raw;
struct {
uint32_t size : 31;
uint32_t not_compressed : 1;
};
};
/* + size bytes of data */ /* + size bytes of data */
/* + uint32_t block_checksum iff has_block_checksum is set */ /* + uint32_t block_checksum iff has_block_checksum is set */
} __packed; } __packed;
@ -114,16 +107,17 @@ size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
return 0; /* input overrun */ return 0; /* input overrun */
/* We assume there's always only a single, standard frame. */ /* We assume there's always only a single, standard frame. */
if (le32toh(h->magic) != LZ4F_MAGICNUMBER || h->version != 1) if (le32toh(h->magic) != LZ4F_MAGICNUMBER
|| (h->flags & VERSION) != (1 << VERSION_SHIFT))
return 0; /* unknown format */ return 0; /* unknown format */
if (h->reserved0 || h->reserved1 || h->reserved2) if ((h->flags & RESERVED0) || (h->block_descriptor & RESERVED1_2))
return 0; /* reserved must be zero */ return 0; /* reserved must be zero */
if (!h->independent_blocks) if (!(h->flags & INDEPENDENT_BLOCKS))
return 0; /* we don't support block dependency */ return 0; /* we don't support block dependency */
has_block_checksum = h->has_block_checksum; has_block_checksum = h->flags & HAS_BLOCK_CHECKSUM;
in += sizeof(*h); in += sizeof(*h);
if (h->has_content_size) if (h->flags & HAS_CONTENT_SIZE)
in += sizeof(uint64_t); in += sizeof(uint64_t);
in += sizeof(uint8_t); in += sizeof(uint8_t);
} }
@ -133,28 +127,28 @@ size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
break; /* input overrun */ break; /* input overrun */
struct lz4_block_header b = { struct lz4_block_header b = {
{ .raw = le32toh(*(const uint32_t *)in) } .raw = le32toh(*(const uint32_t *)in)
}; };
in += sizeof(struct lz4_block_header); in += sizeof(struct lz4_block_header);
if ((size_t)(in - src) + b.size > srcn) if ((size_t)(in - src) + (b.raw & BH_SIZE) > srcn)
break; /* input overrun */ break; /* input overrun */
if (!b.size) { if (!(b.raw & BH_SIZE)) {
out_size = out - dst; out_size = out - dst;
break; /* decompression successful */ break; /* decompression successful */
} }
if (b.not_compressed) { if (b.raw & NOT_COMPRESSED) {
size_t size = MIN((uintptr_t)b.size, (uintptr_t)dst size_t size = MIN((uintptr_t)(b.raw & BH_SIZE), (uintptr_t)dst
+ dstn - (uintptr_t)out); + dstn - (uintptr_t)out);
memcpy(out, in, size); memcpy(out, in, size);
if (size < b.size) if (size < (b.raw & BH_SIZE))
break; /* output overrun */ break; /* output overrun */
out += size; out += size;
} else { } else {
/* constant folding essential, do not touch params! */ /* constant folding essential, do not touch params! */
int ret = LZ4_decompress_generic(in, out, b.size, int ret = LZ4_decompress_generic(in, out, (b.raw & BH_SIZE),
dst + dstn - out, endOnInputSize, dst + dstn - out, endOnInputSize,
full, 0, noDict, out, NULL, 0); full, 0, noDict, out, NULL, 0);
if (ret < 0) if (ret < 0)
@ -162,7 +156,7 @@ size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
out += ret; out += ret;
} }
in += b.size; in += (b.raw & BH_SIZE);
if (has_block_checksum) if (has_block_checksum)
in += sizeof(uint32_t); in += sizeof(uint32_t);
} }