Browse Source

Packed the library for ease of use

master
Ludovic 'Archivist' Lagouardette 2 months ago
parent
commit
7d293e70fd
10 changed files with 939 additions and 12 deletions
  1. +0
    -4
      .gitmodules
  2. +3
    -2
      CMakeLists.txt
  3. +0
    -3
      lib/CMakeLists.txt
  4. +0
    -1
      lib/chck
  5. +1
    -1
      src/CMakeLists.txt
  6. +568
    -0
      src/chck/buffer/buffer.c
  7. +75
    -0
      src/chck/buffer/buffer.h
  8. +133
    -0
      src/chck/buffer/endianess.h
  9. +159
    -0
      src/chck/overflow/overflow.h
  10. +0
    -1
      src/pi9.pc.in

+ 0
- 4
.gitmodules View File

@ -1,4 +0,0 @@
[submodule "chck"]
path = lib/chck
url = git://github.com/Cloudef/chck.git
branch = master

+ 3
- 2
CMakeLists.txt View File

@ -4,7 +4,6 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMake")
# Subprojects
include(subproject)
add_subdirectory(lib)
# CPack
set(CPACK_SYSTEM_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}")
@ -74,7 +73,7 @@ set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_definitions(-D_DEFAULT_SOURCE)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src ${CHCK_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
add_subdirectory(src)
if (PI9_BUILD_BINARIES)
@ -82,6 +81,8 @@ if (PI9_BUILD_BINARIES)
endif ()
file(COPY src/pi9.h src/pi9_string.h DESTINATION include/pi9)
file(COPY src/chck/buffer/buffer.h src/chck/buffer/endianess.h DESTINATION include/chck/buffer)
file(COPY src/chck/overflow/overflow.h DESTINATION include/chck/overflow)
if ("${CMAKE_PROJECT_NAME}" STREQUAL "${PROJECT_NAME}")
feature_summary(WHAT ALL)

+ 0
- 3
lib/CMakeLists.txt View File

@ -1,3 +0,0 @@
set(CHCK_BUILD_STATIC ON CACHE STRING "Build chck statically if not found systemwide" FORCE)
set(CHCK_BUILD_TESTS OFF CACHE STRING "Do not build chck tests" FORCE)
add_subproject(chck Chck)

+ 0
- 1
lib/chck

@ -1 +0,0 @@
Subproject commit 7fd2a7375492c0704286f7073fa22dbfe2218653

+ 1
- 1
src/CMakeLists.txt View File

@ -1,4 +1,4 @@
add_library(pi9 pi9.c pi9_string.c)
add_library(pi9 pi9.c pi9_string.c chck/buffer/buffer.c chck/buffer/buffer.h chck/buffer/endianess.h chck/overflow.h)
target_link_libraries(pi9 PRIVATE ${CHCK_LIBRARIES})
# Parse soversion version

+ 568
- 0
src/chck/buffer/buffer.c View File

@ -0,0 +1,568 @@
#include "buffer.h"
#include <chck/overflow/overflow.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#if HAS_ZLIB
# include <zlib.h>
#elif !defined(HAS_ZLIB)
# define HAS_ZLIB 0
#endif
struct chck_variant {
union {
uint64_t u64;
uint32_t u32;
uint16_t u16;
uint8_t u8;
uint8_t b[sizeof(uint64_t)];
};
enum chck_bits bits;
};
static inline bool
valid_bits(enum chck_bits bits)
{
return (bits == CHCK_BUFFER_B8 ||
bits == CHCK_BUFFER_B16 ||
bits == CHCK_BUFFER_B32 ||
bits == CHCK_BUFFER_B64);
}
static inline enum chck_bits
smallest_bits_for_value(uintmax_t v)
{
static const struct {
uintmax_t off;
enum chck_bits bits;
} map[3] = {
{ ~(uint32_t)0, CHCK_BUFFER_B64 },
{ ~(uint16_t)0, CHCK_BUFFER_B32 },
{ ~(uint8_t)0, CHCK_BUFFER_B16 },
};
for (size_t i = 0; i < sizeof(map) / sizeof(map[0]); ++i) {
if (v <= map[i].off)
continue;
return map[i].bits;
}
return CHCK_BUFFER_B8;
}
static inline uintmax_t
variant_get_value(struct chck_variant v)
{
switch (v.bits) {
case CHCK_BUFFER_B8:
return v.u8;
case CHCK_BUFFER_B16:
return v.u16;
case CHCK_BUFFER_B32:
return v.u32;
case CHCK_BUFFER_B64:
return v.u64;
}
assert(0 && "should not happen");
return 0;
}
void
chck_buffer_flush(struct chck_buffer *buf)
{
assert(buf);
if (buf->copied)
free(buf->buffer);
buf->copied = false;
buf->curpos = buf->buffer = NULL;
}
void
chck_buffer_release(struct chck_buffer *buf)
{
if (!buf)
return;
chck_buffer_flush(buf);
*buf = (struct chck_buffer){0};
}
bool
chck_buffer_from_pointer(struct chck_buffer *buf, void *ptr, size_t size, enum chck_endianess endianess)
{
assert(buf);
*buf = (struct chck_buffer){ .step = 32 };
chck_buffer_set_pointer(buf, ptr, size, endianess);
return true;
}
bool
chck_buffer(struct chck_buffer *buf, size_t size, enum chck_endianess endianess)
{
assert(buf);
void *data = NULL;
if (size > 0 && !(data = malloc(size)))
return false;
if (unlikely(!chck_buffer_from_pointer(buf, data, size, endianess)))
goto fail;
buf->copied = true;
return true;
fail:
free(data);
return false;
}
void
chck_buffer_set_pointer(struct chck_buffer *buf, void *ptr, size_t size, enum chck_endianess endianess)
{
assert(buf);
if (buf->copied) {
free(buf->buffer);
buf->buffer = NULL;
}
if (endianess == CHCK_ENDIANESS_NATIVE) {
buf->endianess = chck_endianess();
} else {
buf->endianess = endianess;
}
buf->size = size;
buf->buffer = buf->curpos = ptr;
buf->copied = false;
}
bool
chck_buffer_resize(struct chck_buffer *buf, size_t size)
{
assert(buf);
if (unlikely(size == buf->size))
return true;
if (unlikely(size == 0)) {
chck_buffer_flush(buf);
return true;
}
uint8_t *tmp;
if (!(tmp = realloc((buf->copied ? buf->buffer : NULL), size)))
return false;
/* set new buffer position */
if (buf->curpos - buf->buffer > (ptrdiff_t)size) {
buf->curpos = tmp + (buf->size - size);
} else {
buf->curpos = tmp + (buf->curpos - buf->buffer);
}
buf->size = size;
buf->buffer = tmp;
buf->copied = true;
return true;
}
ptrdiff_t
chck_buffer_seek(struct chck_buffer *buf, long offset, int whence)
{
assert(buf);
assert(whence == SEEK_SET || whence == SEEK_END || whence == SEEK_CUR);
switch (whence) {
case SEEK_SET:
if (buf->buffer + offset > buf->buffer + buf->size) {
buf->curpos = buf->buffer + buf->size;
} else if (offset >= 0) {
buf->curpos = buf->buffer + offset;
}
break;
case SEEK_CUR:
if (buf->curpos + offset > buf->buffer + buf->size) {
buf->curpos = buf->curpos + buf->size;
} else if (buf->curpos + offset < buf->buffer) {
buf->curpos = buf->buffer;
} else {
buf->curpos = buf->curpos + offset;
}
break;
case SEEK_END:
buf->curpos = buf->buffer + buf->size;
break;
default:break;
}
return buf->curpos - buf->buffer;
}
static bool
bounds_check(struct chck_buffer *buf, size_t size, size_t memb)
{
size_t nsz;
if (unlikely(chck_mul_ofsz(size, memb, &nsz)))
return false;
const size_t sz = buf->size - (buf->curpos - buf->buffer);
if (nsz > sz) {
/* buf->size + size * memb + buf->step */
if (unlikely(chck_add_ofsz(buf->size, nsz, &nsz)) || unlikely(chck_add_ofsz(buf->step, nsz, &nsz)))
return false;
if (!chck_buffer_resize(buf, nsz))
return false;
}
return true;
}
size_t
chck_buffer_fill(const void *src, size_t size, size_t memb, struct chck_buffer *buf)
{
assert(src && buf);
if (!bounds_check(buf, size, memb) || !buf->curpos || !src)
return 0;
memcpy(buf->curpos, src, size * memb);
return memb;
}
size_t
chck_buffer_fill_from_file(FILE *src, size_t size, size_t memb, struct chck_buffer *buf)
{
assert(src && buf);
if (!bounds_check(buf, size, memb) || !buf->curpos || !src)
return 0;
return fread(buf->curpos, size, memb, src);
}
size_t
chck_buffer_fill_from_fd(int fd, size_t size, size_t memb, struct chck_buffer *buf)
{
assert(fd && buf);
if (!bounds_check(buf, size, memb) || !buf->curpos)
return 0;
const ssize_t ret = read(fd, buf->curpos, size * memb);
if (unlikely(ret == -1 || ret == 0))
return 0;
return (size_t)ret / size;
}
size_t
chck_buffer_read(void *dst, size_t size, size_t memb, struct chck_buffer *buf)
{
assert(dst && buf);
size_t nsz;
if (unlikely(chck_mul_ofsz(size, memb, &nsz)))
return 0;
if (unlikely(nsz > buf->size - (buf->curpos - buf->buffer))) {
assert(size != 0); // should never happen
// read as much as we can
memb = (buf->size - (buf->curpos - buf->buffer)) / size;
}
memcpy(dst, buf->curpos, size * memb);
buf->curpos += size * memb;
return memb;
}
bool
chck_buffer_read_int(void *i, enum chck_bits bits, struct chck_buffer *buf)
{
assert(i && buf);
if (!valid_bits(bits))
return false;
if (unlikely(chck_buffer_read(i, bits, 1, buf) != 1))
return false;
if (!chck_buffer_native_endianess(buf))
chck_bswap_single(i, bits);
return true;
}
bool
chck_buffer_read_string_of_type(char **str, size_t *out_len, enum chck_bits bits, struct chck_buffer *buf)
{
assert(buf && str);
*str = NULL;
if (out_len)
*out_len = 0;
struct chck_variant v = { .bits = bits };
if (unlikely(!chck_buffer_read_int(v.b, bits, buf)))
return false;
const size_t len = variant_get_value(v);
if (out_len)
*out_len = len;
if (len <= 0)
return true;
if (!(*str = chck_calloc_add_of(len, 1)))
return false;
if (unlikely(chck_buffer_read(*str, 1, len, buf) != len)) {
free(*str);
return false;
}
return true;
}
bool
chck_buffer_read_string(char **str, size_t *len, struct chck_buffer *buf)
{
assert(str && buf);
*str = NULL;
if (len)
*len = 0;
uint8_t bits;
if (unlikely(!chck_buffer_read_int(&bits, sizeof(bits), buf)))
return false;
return likely(chck_buffer_read_string_of_type(str, len, bits, buf));
}
size_t
chck_buffer_write(const void *src, size_t size, size_t memb, struct chck_buffer *buf)
{
memb = chck_buffer_fill(src, size, memb, buf);
buf->curpos += size * memb;
return memb;
}
size_t
chck_buffer_write_from_file(FILE *src, size_t size, size_t memb, struct chck_buffer *buf)
{
memb = chck_buffer_fill_from_file(src, size, memb, buf);
buf->curpos += size * memb;
return memb;
}
size_t
chck_buffer_write_from_fd(int fd, size_t size, size_t memb, struct chck_buffer *buf)
{
memb = chck_buffer_fill_from_fd(fd, size, memb, buf);
buf->curpos += size * memb;
return memb;
}
bool
chck_buffer_write_int(const void *i, enum chck_bits bits, struct chck_buffer *buf)
{
assert(buf);
if (!valid_bits(bits))
return false;
bool ret;
if (!chck_buffer_native_endianess(buf)) {
uint8_t b[sizeof(uint64_t)];
memcpy(b, i, bits);
chck_bswap_single(b, bits);
ret = (chck_buffer_write(b, bits, 1, buf) == 1);
} else {
ret = (chck_buffer_write(i, bits, 1, buf) == 1);
}
return ret;
}
bool
chck_buffer_write_string_of_type(const char *str, size_t len, enum chck_bits bits, struct chck_buffer *buf)
{
assert(buf);
bool ret = false;
switch (bits) {
case CHCK_BUFFER_B8:
ret = chck_buffer_write_int((uint8_t[]){len}, bits, buf);
break;
case CHCK_BUFFER_B16:
ret = chck_buffer_write_int((uint16_t[]){len}, bits, buf);
break;
case CHCK_BUFFER_B32:
ret = chck_buffer_write_int((uint32_t[]){len}, bits, buf);
break;
case CHCK_BUFFER_B64:
ret = chck_buffer_write_int((uint64_t[]){len}, bits, buf);
break;
}
if (unlikely(!ret))
return false;
return likely(chck_buffer_write(str, 1, len, buf) == len);
}
bool
chck_buffer_write_string(const char *str, size_t len, struct chck_buffer *buf)
{
assert(buf);
const uint8_t bits = smallest_bits_for_value(len);
if (unlikely(!chck_buffer_write_int(&bits, sizeof(bits), buf)))
return false;
return likely(chck_buffer_write_string_of_type(str, len, bits, buf));
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
size_t
chck_buffer_write_format(struct chck_buffer *buf, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
const size_t wrote = chck_buffer_write_varg(buf, fmt, argp);
va_end(argp);
return wrote;
}
size_t
chck_buffer_write_varg(struct chck_buffer *buf, const char *fmt, va_list args)
{
va_list cpy;
va_copy(cpy, args);
char *str = NULL;
const size_t len = vsnprintf(NULL, 0, fmt, args);
if (len > 0 && !(str = chck_malloc_add_of(len, 1))) {
va_end(cpy);
return false;
}
vsnprintf(str, len + 1, fmt, cpy);
va_end(cpy);
const size_t wrote = chck_buffer_write(str, 1, len, buf);
free(str);
return wrote;
}
#pragma GCC diagnostic pop
bool
chck_buffer_has_zlib(void)
{
return HAS_ZLIB;
}
#pragma GCC diagnostic ignored "-Wsuggest-attribute=const"
bool
chck_buffer_compress_zlib(struct chck_buffer *buf)
{
#if HAS_ZLIB
uLongf dsize, bsize;
dsize = bsize = compressBound(buf->size);
void *compressed;
if (!(compressed = malloc(dsize)))
return false;
int ret;
while ((ret = compress(compressed, &dsize, buf->buffer, buf->size)) == Z_BUF_ERROR) {
void *tmp;
if (!(tmp = chck_realloc_mul_of(compressed, bsize, 2)))
goto fail;
compressed = tmp;
dsize = (bsize *= 2);
}
if (unlikely(ret != Z_OK))
goto fail;
chck_buffer_set_pointer(buf, compressed, bsize, buf->endianess);
buf->copied = true;
if (buf->size > dsize)
chck_buffer_resize(buf, dsize);
return true;
fail:
free(compressed);
return false;
#else
(void)buf;
return false;
#endif
}
bool
chck_buffer_decompress_zlib(struct chck_buffer *buf)
{
#if HAS_ZLIB
uLongf dsize, bsize;
{
size_t sz;
if (unlikely(chck_mul_ofsz(buf->size, 2, &sz)) || (uLongf)sz < sz)
return false;
dsize = bsize = sz;
}
if (!dsize)
return false;
void *decompressed;
if (!(decompressed = malloc(dsize)))
return false;
int ret;
while ((ret = uncompress(decompressed, &dsize, buf->buffer, buf->size)) == Z_BUF_ERROR) {
void *tmp;
if (!(tmp = chck_realloc_mul_of(decompressed, bsize, 2)))
goto fail;
decompressed = tmp;
dsize = (bsize *= 2);
}
if (unlikely(ret != Z_OK))
goto fail;
chck_buffer_set_pointer(buf, decompressed, bsize, buf->endianess);
buf->copied = true;
if (bsize > dsize)
chck_buffer_resize(buf, dsize);
return true;
fail:
free(decompressed);
return false;
#else
(void)buf;
return false;
#endif
}

+ 75
- 0
src/chck/buffer/buffer.h View File

@ -0,0 +1,75 @@
#ifndef __chck_buffer__
#define __chck_buffer__
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include "endianess.h"
enum chck_bits {
CHCK_BUFFER_B8 = sizeof(int8_t),
CHCK_BUFFER_B16 = sizeof(int16_t),
CHCK_BUFFER_B32 = sizeof(int32_t),
CHCK_BUFFER_B64 = sizeof(int64_t),
};
struct chck_buffer {
// pointer to current buffer and the current position
uint8_t *buffer, *curpos;
// size of the buffer
size_t size;
// growth step for the buffer incase writing to full buffer
size_t step;
// endianess true == big, false == little
bool endianess;
// copied == true, means that buffer is owned by this struct and will be freed on chck_buffer_release
bool copied;
};
static inline bool
chck_buffer_native_endianess(const struct chck_buffer *buf)
{
return (chck_endianess() == buf->endianess);
}
void chck_buffer_release(struct chck_buffer *buf);
void chck_buffer_flush(struct chck_buffer *buf);
bool chck_buffer_from_pointer(struct chck_buffer *buf, void *ptr, size_t size, enum chck_endianess endianess);
bool chck_buffer(struct chck_buffer *buf, size_t size, enum chck_endianess endianess);
void chck_buffer_set_pointer(struct chck_buffer *buf, void *ptr, size_t size, enum chck_endianess endianess);
size_t chck_buffer_fill(const void *src, size_t size, size_t memb, struct chck_buffer *buf);
size_t chck_buffer_fill_from_file(FILE *src, size_t size, size_t memb, struct chck_buffer *buf);
size_t chck_buffer_fill_from_fd(int fd, size_t size, size_t memb, struct chck_buffer *buf);
size_t chck_buffer_write(const void *src, size_t size, size_t nmemb, struct chck_buffer *buf);
size_t chck_buffer_write_from_file(FILE *src, size_t size, size_t nmemb, struct chck_buffer *buf);
size_t chck_buffer_write_from_fd(int fd, size_t size, size_t nmemb, struct chck_buffer *buf);
size_t chck_buffer_read(void *dst, size_t size, size_t memb, struct chck_buffer *buf);
bool chck_buffer_read_int(void *i, enum chck_bits bits, struct chck_buffer *buf);
bool chck_buffer_read_string(char **str, size_t *len, struct chck_buffer *buf);
bool chck_buffer_read_string_of_type(char **str, size_t *len, enum chck_bits bits, struct chck_buffer *buf);
bool chck_buffer_write_int(const void *i, enum chck_bits bits, struct chck_buffer *buf);
bool chck_buffer_write_string(const char *str, size_t len, struct chck_buffer *buf);
bool chck_buffer_write_string_of_type(const char *str, size_t len, enum chck_bits bits, struct chck_buffer *buf);
CHCK_FORMAT(printf, 2, 3) size_t chck_buffer_write_format(struct chck_buffer *buf, const char *fmt, ...);
size_t chck_buffer_write_varg(struct chck_buffer *buf, const char *fmt, va_list args);
ptrdiff_t chck_buffer_seek(struct chck_buffer *buf, long offset, int whence);
bool chck_buffer_resize(struct chck_buffer *buf, size_t size);
/* -DHAS_ZLIB=1 -lz */
bool chck_buffer_has_zlib(void);
bool chck_buffer_compress_zlib(struct chck_buffer *buf);
bool chck_buffer_decompress_zlib(struct chck_buffer *buf);
#endif /* __chck_buffer__ */

+ 133
- 0
src/chck/buffer/endianess.h View File

@ -0,0 +1,133 @@
#ifndef __chck_endianess__
#define __chck_endianess__
#include <chck/macros.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
enum chck_endianess {
CHCK_ENDIANESS_LITTLE = 0,
CHCK_ENDIANESS_BIG = 1,
CHCK_ENDIANESS_NATIVE = 2,
};
#if defined(__clang__) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 3 && !defined(__MINGW32__) && !defined(__MINGW64__))
# define bswap16 __builtin_bswap16
# define bswap32 __builtin_bswap32
# define bswap64 __builtin_bswap64
# define HAS_BYTESWAP 1
#elif defined(__GLIBC__)
# include <byteswap.h>
# define bswap16 __bswap_16
# define bswap32 __bswap_32
# define bswap64 __bswap_64
# define HAS_BYTESWAP 1
#elif defined(__NetBSD__)
# include <sys/types.h>
# include <machine/bswap.h> /* already named bswap16/32/64 */
# define HAS_BYTESWAP 1
#elif defined(_MSC_VER)
# define bswap16 _byteswap_ushort
# define bswap32 _byteswap_ulong
# define bswap64 _byteswap_uint64
# define HAS_BYTESWAP 1
#else
# define HAS_BYTESWAP 0
#endif
#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
(defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN) || \
defined(__BIG_ENDIAN__) || \
defined(__ARMEB__) || \
defined(__THUMBEB__) || \
defined(__AARCH64EB__) || \
defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
// compiletime big endian
# define chck_endianess() CHCK_ENDIANESS_BIG
#elif (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
(defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || \
defined(__LITTLE_ENDIAN__) || \
defined(__ARMEL__) || \
defined(__THUMBEL__) || \
defined(__AARCH64EL__) || \
defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
// compiletime little endian
# define chck_endianess() CHCK_ENDIANESS_LITTLE
#else
// runtime endianess check
static inline enum
chck_endianess chck_endianess(void)
{
union {
uint32_t i;
char c[4];
} bint = { 0x01020304 };
return (bint.c[0] == 1 ? CHCK_ENDIANESS_BIG : CHCK_ENDIANESS_LITTLE);
};
#endif
static inline void
chck_bswap_generic(void *p, size_t size)
{
if (size <= sizeof(uint8_t))
return;
assert(size <= sizeof(intmax_t));
uint8_t b[sizeof(intmax_t)];
memcpy(b, p, size);
for (size_t s = 0; s < size; ++s)
memset((uint8_t*)p + s, b[size - s - 1], 1);
}
static inline void
chck_bswap_single(void *p, size_t size)
{
#if HAS_BYTESWAP
assert(p);
switch (size) {
case sizeof(uint32_t):
*((uint32_t*)p) = bswap32(*((uint32_t*)p));
break;
case sizeof(uint16_t):
*((uint16_t*)p) = bswap16(*((uint16_t*)p));
break;
case sizeof(uint64_t):
*((uint64_t*)p) = bswap64(*((uint64_t*)p));
break;
default:
chck_bswap_generic(p, size);
break;
}
#else
chck_bswap_generic(p, size);
#endif
}
static inline void
chck_bswap(void *v, size_t size, size_t memb)
{
assert(v);
for (uint8_t *p = v; size > sizeof(uint8_t) && p < (uint8_t*)v + (memb * size); p += size)
chck_bswap_single(p, size);
}
/** define chck_bswap{16,32,64} for use **/
#if HAS_BYTESWAP
# define generic_swap(T, n) \
static inline T chck_bswap##n(T v) { return bswap##n(v); }
#else
# define generic_swap(T, n) \
static inline T chck_bswap##n(T v) { chck_bswap_generic(&v, sizeof(v)); return v; }
#endif
generic_swap(uint16_t, 16)
generic_swap(uint32_t, 32)
generic_swap(uint64_t, 64)
#undef generic_swap
#endif /* __chck_endianess__ */

+ 159
- 0
src/chck/overflow/overflow.h View File

@ -0,0 +1,159 @@
#ifndef __chck_overflow_h__
#define __chck_overflow_h__
#include <chck/macros.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
/** clang feature detection. */
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
#if __GNUC__ >= 5 || __has_builtin(__builtin_add_overflow)
/** assume clang and gcc (>=5) to only have builtins for now. */
# define add_of(a, b, r) __builtin_add_overflow(a, b, r)
# define sub_of(a, b, r) __builtin_sub_overflow(a, b, r)
# define mul_of(a, b, r) __builtin_mul_overflow(a, b, r)
# define of_attr
#else
/** else use these generics, note behaviour of these is not strictly defined. */
# define add_of(a, b, r) ((*(r) = ((a) + (b))) < (a))
# define sub_of(a, b, r) ((*(r) = ((a) - (b))) > (a))
# define mul_of(a, b, r) (((*(r) = ((a) * (b))) || *(r) == 0) && ((a) != 0 && (b) > *(r) / (a)))
# if __clang__
# define of_attr __attribute__((optnone)) // Do not optimize above checks, in most systems this will work, but not defined.
# warning "Using non compiler builtins for overflow checks, this will be undefined for signed integers"
# elif __GNUC__
# define of_attr __attribute__((optimize("wrapv"))) // in older GCC we can make this behavior defined
# else
# warning "Using non compiler builtins for overflow checks, this will be undefined for signed integers"
# endif
#endif
/** declare overflow functions */
// T = type name, n = function suffix, s = is type signed?
#define decl_generics_for_type(T, n, s) \
of_attr static inline bool chck_add_of##n(T a, T b, T *r) { assert((!s || b >= 0) && r); return add_of(a, b, r); } \
of_attr static inline bool chck_sub_of##n(T a, T b, T *r) { assert((!s || b >= 0) && r); return sub_of(a, b, r); } \
of_attr static inline bool chck_mul_of##n(T a, T b, T *r) { assert(r); return mul_of(a, b, r); }
// UT = unsigned type, un = unsigned function suffix
// T = signed type, n = signed function suffix
#define decl_generics(UT, un, T, n) \
decl_generics_for_type(UT, un, false) \
decl_generics_for_type(T, n, true)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
decl_generics_for_type(size_t, sz, false)
decl_generics(uint64_t, u64, int64_t, 64)
decl_generics(uint32_t, u32, int32_t, 32)
decl_generics(uint16_t, u16, int16_t, 16)
decl_generics(uint8_t, u8, int8_t, 8)
#pragma GCC diagnostic pop
#undef decl_generics
#undef decl_generics_for_type
#undef add_of
#undef sub_of
#undef mul_of
#undef of_attr
CHCK_MALLOC static inline void*
chck_malloc_add_of(size_t size, size_t add)
{
size_t r;
if (unlikely(chck_add_ofsz(size, add, &r)) || !r)
return NULL;
return malloc(r);
}
CHCK_MALLOC static inline void*
chck_malloc_sub_of(size_t size, size_t sub)
{
size_t r;
if (unlikely(chck_sub_ofsz(size, sub, &r)) || !r)
return NULL;
return malloc(r);
}
CHCK_MALLOC static inline void*
chck_malloc_mul_of(size_t size, size_t mul)
{
size_t r;
if (unlikely(chck_mul_ofsz(size, mul, &r)) || !r)
return NULL;
return malloc(r);
}
CHCK_MALLOC static inline void*
chck_calloc_of(size_t nmemb, size_t size)
{
size_t r;
if (unlikely(chck_mul_ofsz(nmemb, size, &r)) || !r)
return NULL;
return calloc(nmemb, size);
}
CHCK_MALLOC static inline void*
chck_calloc_add_of(size_t size, size_t add)
{
size_t r;
if (unlikely(chck_add_ofsz(size, add, &r)) || !r)
return NULL;
return calloc(1, r);
}
CHCK_MALLOC static inline void*
chck_calloc_sub_of(size_t size, size_t sub)
{
size_t r;
if (unlikely(chck_sub_ofsz(size, sub, &r)) || !r)
return NULL;
return calloc(1, r);
}
static inline void*
chck_realloc_add_of(void *ptr, size_t size, size_t add)
{
size_t r;
if (unlikely(chck_add_ofsz(size, add, &r)) || !r)
return NULL;
return realloc(ptr, r);
}
static inline void*
chck_realloc_sub_of(void *ptr, size_t size, size_t sub)
{
size_t r;
if (unlikely(chck_sub_ofsz(size, sub, &r)) || !r)
return NULL;
return realloc(ptr, r);
}
static inline void*
chck_realloc_mul_of(void *ptr, size_t size, size_t mul)
{
size_t r;
if (unlikely(chck_mul_ofsz(size, mul, &r)) || !r)
return NULL;
return realloc(ptr, r);
}
#endif /* __chck_overflow_h__ */

+ 0
- 1
src/pi9.pc.in View File

@ -6,6 +6,5 @@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: @PROJECT_NAME@
Description: 9p server abstraction library
Version: @PROJECT_VERSION@
Requires.private: chck
Libs: -L${libdir} -lpi9
Cflags: -I${includedir}

Loading…
Cancel
Save