Skip to content

Commit

Permalink
Add a plain build variant
Browse files Browse the repository at this point in the history
This is essentially a glorified (ctx << 32 | errno). Why one might use
this build variant though is to keep the same error code generation call
sites even if the compiler doesn't support the pre-requisite features
for the full merr. Alternatively, a library may have too many source
files, in which case merr would return garbage most likely. What that
upper limit on source files is yet to be discovered.
  • Loading branch information
tristan957 committed Aug 25, 2023
1 parent 91c6368 commit 4725704
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 46 deletions.
13 changes: 9 additions & 4 deletions .github/workflows/builds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,25 @@ concurrency:
jobs:
normal:
runs-on: ubuntu-latest
container: quay.io/fedora/fedora:38
strategy:
fail-fast: true
matrix:
buildtype: [debug, release]
plain: [enabled, disabled]

steps:
- name: Install dependencies
run: |
sudo apt-get install -y meson
dnf install --assumeyes gcc meson
- name: Checkout libmerr
uses: actions/checkout@v3

- name: Setup
run: |
meson setup build --fatal-meson-warnings --werror \
--buildtype=${{ matrix.buildtype }}
--buildtype=${{ matrix.buildtype }} -Dplain=${{ matrix.plain }}
- name: Build
run: |
Expand All @@ -66,23 +68,26 @@ jobs:
asan-ubsan:
runs-on: ubuntu-latest
container: quay.io/fedora/fedora:38
strategy:
fail-fast: true
matrix:
buildtype: [debug, release]
plain: [enabled, disabled]

steps:
- name: Install dependencies
run: |
sudo apt-get install -y meson
dnf install --assumeyes gcc meson libasan libubsan
- name: Checkout libmerr
uses: actions/checkout@v3

- name: Setup
run: |
meson setup build --fatal-meson-warnings --werror \
--buildtype=${{ matrix.buildtype }} -Db_sanitize=address,undefined
--buildtype=${{ matrix.buildtype }} -Db_sanitize=address,undefined \
-Dplain=${{ matrix.plain }}
- name: Build
run: |
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ permissions:
jobs:
codeql:
runs-on: ubuntu-latest
container: quay.io/fedora/fedora:38

steps:
- name: Install dependencies
run: |
sudo apt-get install -y meson
sudo apt-get install -y gcc meson
- name: Checkout libmerr
uses: actions/checkout@v3
Expand Down
91 changes: 72 additions & 19 deletions include/merr.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,7 @@ extern "C" {
#include <stdint.h>

#ifndef __has_attribute
#error "__has_attribute must be provided by the compiler"
#endif

#if !__has_attribute(aligned)
#error "Copmiler must support the aligned attribute"
#endif

#if !__has_attribute(section)
#error "Compiler must support the section attribute"
#define __has_attribute(_attr) 0
#endif

#if __has_attribute(always_inline)
Expand All @@ -50,23 +42,39 @@ extern "C" {
#define MERR_WARN_UNUSED_RESULT
#endif

#ifndef MERR_PLAIN
// Alignment of merr_curr_file in section "merr"
#define MERR_MAX_PATH_LENGTH (1 << 6)

#define merr_attributes __attribute__((section("merr"))) __attribute__((aligned(MERR_MAX_PATH_LENGTH)))

static char merr_curr_file[MERR_MAX_PATH_LENGTH] merr_attributes MERR_USED = __BASE_FILE__;

#endif


/* Layout of merr_t:
*
* Field #bits Description
* ------ ----- ----------
* 63..48 16 signed offset of (merr_curr_file - merr_base) / MERR_MAX_PATH_LENGTH
* 47..32 16 line number
* 31..16 16 context
* 15..0 16 error value
* If the compiler supports both the section and aligned attributes and
* MERR_PLAIN was not requested:
*
* Field #bits Description
* ------ ----- ----------
* 63..48 16 signed offset of (merr_curr_file - merr_base) / MERR_MAX_PATH_LENGTH
* 47..32 16 line number
* 31..16 16 context
* 15..0 16 error value
*
* If the compiler does not support either of the section or aligned
* attributes, or MERR_PLAIN was requested:
*
* Field #bits Description
* ------ ----- ----------
* 63..32 32 context
* 31..0 32 error value
*/

#ifndef MERR_PLAIN

#define MERR_FILE_SHIFT 48
#define MERR_LINE_SHIFT 32
#define MERR_CTX_SHIFT 16
Expand All @@ -76,6 +84,18 @@ static char merr_curr_file[MERR_MAX_PATH_LENGTH] merr_attributes MERR_USED = __B
#define MERR_CTX_MASK 0x00000000ffff0000LL
#define MERR_ERRNO_MASK 0x000000000000ffffLL

#define MERR_CTX_TYPE int16_t

#else

#define MERR_CTX_SHIFT 32

#define MERR_ERRNO_MASK 0x00000000ffffffffLL

#define MERR_CTX_TYPE int32_t

#endif

/**
* @brief The error value type.
*/
Expand Down Expand Up @@ -108,6 +128,8 @@ merr_stringify(int num);
*/
#define merr(_errnum) merrx((_errnum), 0)

#ifndef MERR_PLAIN

/**
* @brief Pack given error number, call-site info, and context into an merr_t.
*
Expand All @@ -117,16 +139,33 @@ merr_stringify(int num);
*/
#define merrx(_errnum, _ctx) merr_pack((_errnum), (_ctx), merr_curr_file, __LINE__)

#else

/**
* @brief Pack given error number and context into an merr_t.
*
* @param _errnum Error number.
* @param _ctx Context.
* @returns An merr_t.
*/
#define merrx(_errnum, _ctx) merr_pack((_errnum), (_ctx))

#endif

/**
* @brief Get the context.
*
* @param err Error.
* @returns Error context.
*/
static MERR_ALWAYS_INLINE int16_t MERR_CONST MERR_USED MERR_WARN_UNUSED_RESULT
static MERR_ALWAYS_INLINE MERR_CTX_TYPE MERR_CONST MERR_USED MERR_WARN_UNUSED_RESULT
merr_ctx(const merr_t err)
{
return (int16_t)((err & MERR_CTX_MASK) >> MERR_CTX_SHIFT);
#ifndef MERR_PLAIN
return (MERR_CTX_TYPE)((err & MERR_CTX_MASK) >> MERR_CTX_SHIFT);
#else
return (MERR_CTX_TYPE)(err >> MERR_CTX_SHIFT);
#endif
}

/**
Expand All @@ -138,9 +177,11 @@ merr_ctx(const merr_t err)
static MERR_ALWAYS_INLINE int MERR_CONST MERR_USED MERR_WARN_UNUSED_RESULT
merr_errno(const merr_t err)
{
return err & MERR_ERRNO_MASK;
return (int)(err & MERR_ERRNO_MASK);
}

#ifndef MERR_PLAIN

/**
* @brief Get the file name the error was generated in.
*
Expand All @@ -165,6 +206,8 @@ merr_lineno(const merr_t err)
return (uint16_t)((err & MERR_LINE_MASK) >> MERR_LINE_SHIFT);
}

#endif

/**
* @brief Format file, line, ctx, and errno from an merr_t into a buffer.
*
Expand All @@ -187,10 +230,20 @@ merr_strerrorx(merr_t err, char *buf, size_t buf_sz, merr_stringify ctx_stringif
*/
#define merr_strerror(_err, _buf, _buf_sz) merr_strerrorx((_err), (_buf), (_buf_sz), NULL)

#ifndef MERR_PLAIN

// This is not public API. DO NOT USE.
merr_t
merr_pack(int errnum, int ctx, const char *file, uint16_t line) MERR_CONST MERR_WARN_UNUSED_RESULT;

#else

// This is not public API. DO NOT USE.
merr_t
merr_pack(int errnum, int ctx) MERR_CONST MERR_WARN_UNUSED_RESULT;

#endif

#ifdef __cplusplus
}
#endif
Expand Down
60 changes: 45 additions & 15 deletions lib/merr.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@
#define MERR_UNUSED
#endif

#ifndef MERR_PLAIN
char merr_base[MERR_MAX_PATH_LENGTH] merr_attributes = "merr_base";
char merr_bug0[MERR_MAX_PATH_LENGTH] merr_attributes = "merr_bug0";
char merr_bug1[MERR_MAX_PATH_LENGTH] merr_attributes = "merr_bug1";
char merr_bug2[MERR_MAX_PATH_LENGTH] merr_attributes = "merr_bug2";

extern uint8_t __start_merr;
extern uint8_t __stop_merr;
#endif

#ifndef HAVE_STRLCPY

Expand Down Expand Up @@ -54,6 +56,8 @@ strlcpy(char * const dst, const char * const src, const size_t sz)

#endif

#ifndef MERR_PLAIN

const char *
merr_file(const merr_t err)
{
Expand Down Expand Up @@ -114,6 +118,27 @@ merr_pack(const int errnum, const int ctx, const char *file, const uint16_t line
return err;
}

#else

merr_t
merr_pack(const int errnum, const int ctx)
{
merr_t err = 0;

if (errnum == 0)
return 0;

if (errnum < INT32_MIN || errnum > INT32_MAX || ctx < INT32_MIN || ctx > INT32_MAX)
return merr(EINVAL);

err |= ((int64_t)ctx << MERR_CTX_SHIFT);
err |= (int64_t)errnum & MERR_ERRNO_MASK;

return err;
}

#endif

static size_t
strerror_safe(const merr_t err, char * const buf, const size_t buf_sz)
{
Expand All @@ -138,33 +163,38 @@ size_t
merr_strerrorx(const merr_t err, char * const buf, size_t buf_sz, merr_stringify ctx_stringify)
{
int ret;
int16_t ctx;
size_t sz = 0;
const char *file;
MERR_CTX_TYPE ctx;

if (!buf && buf_sz > 0)
buf_sz = 0;

if (!err)
return strlcpy(buf, "Success", buf_sz);

file = merr_file(err);
if (file) {
const char *ptr;
#ifndef MERR_PLAIN
{
const char *file;

// Protect against files that may be too long.
ptr = memchr(file, '\0', MERR_MAX_PATH_LENGTH);
ret = snprintf(
buf, buf_sz, "%*s:%d: ", (int)(ptr ? ptr - file : MERR_MAX_PATH_LENGTH), file,
merr_lineno(err));
file = merr_file(err);
if (file) {
const char *ptr;

if (ret < 0) {
sz = strlcpy(buf, "<failed to format the error message>", buf_sz);
goto out;
}
// Protect against files that may be too long.
ptr = memchr(file, '\0', MERR_MAX_PATH_LENGTH);
ret = snprintf(
buf, buf_sz, "%*s:%d: ", (int)(ptr ? ptr - file : MERR_MAX_PATH_LENGTH), file,
merr_lineno(err));

sz += (size_t)ret;
if (ret < 0) {
sz = strlcpy(buf, "<failed to format the error message>", buf_sz);
goto out;
}

sz += (size_t)ret;
}
}
#endif

if (sz >= buf_sz) {
sz += strerror_safe(err, NULL, 0);
Expand Down
15 changes: 15 additions & 0 deletions lib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,22 @@ configure_file(
}
)

cc_has_aligned = cc.has_function_attribute('aligned')
cc_has_section = cc.has_function_attribute('section')
if get_option('plain').disabled() and (not cc_has_aligned or not cc_has_section)
error('Compiler must support both aligned' +
' and section attributes if -Dplain=disabled')
endif

c_args = []
if get_option('plain').enabled() or not cc_has_aligned or not cc_has_section
c_args += '-DMERR_PLAIN'
endif

libmerr = static_library(
'merr',
'merr.c',
c_args: c_args,
include_directories: libmerr_includes,
install: true,
gnu_symbol_visibility: 'hidden'
Expand All @@ -25,6 +38,7 @@ variables = {
}

libmerr_dep = declare_dependency(
compile_args: c_args,
link_with: libmerr,
include_directories: libmerr_includes,
variables: variables
Expand All @@ -38,6 +52,7 @@ if pkg.found()
name: meson.project_name(),
description: 'C99+ library for error information',
url: 'https://github.com/tristan957/libmerr',
extra_cflags: c_args,
variables: variables
)
endif
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ project(
'c_std=c99',
'warning_level=3',
],
meson_version: '>= 0.59.0'
meson_version: '>= 0.63.0'
)

fs = import('fs', required: get_option('tests'))
Expand Down
Loading

0 comments on commit 4725704

Please sign in to comment.