Skip to content

Conversation

maribu
Copy link
Member

@maribu maribu commented Apr 22, 2021

Contribution description

Implement a large chunk of the previous preprocessor magic used to
implement assert() as static inline C function instead. This function
is used to implement the assert() macro. As result, the C compiler
has more optimization opportunities. With GCC 10.2.0, this results
in a slight reduction of ROM.

Testing procedure

A test application was added in tests/core_assert that tests assert() for correct behavior with both NDEBUG defined and without.

Issues/PRs references

None

@maribu maribu requested a review from kaspar030 as a code owner April 22, 2021 19:41
@maribu maribu requested review from gschorcht and miri64 April 22, 2021 19:42
@maribu maribu added Area: core Area: RIOT kernel. Handle PRs marked with this with care! Process: needs >1 ACK Integration Process: This PR requires more than one ACK Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation labels Apr 22, 2021
@maribu
Copy link
Member Author

maribu commented Apr 23, 2021

This changes the semantics for expressions in assert that do have side effects, as the side effects will still trigger with NDEBUG.

However, I think the new behavior is actually convenient in many cases. I will call it assert_ng() and keep an assert() with correct semantics.

A use case for assert_ng(): assert_ng(foo_init() == 0) will still init foo with NDEBUG, just the check will be optimized out.

@maribu maribu added Type: new feature The issue requests / The PR implemements a new feature for RIOT and removed Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation labels Apr 23, 2021
@maribu maribu changed the title core/assert: implement in (mostly) C core: add assert_ng() and refactor assert() Apr 23, 2021
@maribu
Copy link
Member Author

maribu commented Apr 23, 2021

In a follow up all instances of

void foo(int bar)
{
    (void)bar;
    assert(bar == 42);
}

can be converted to

void foo(int bar)
{
    assert_ng(bar == 42);
}

And all instances of

void foo(void)
{
    int retval = bar_init();
    (void)retval;
    assert(retval == 0);
}

can be converted to

void foo(void)
{
    assert_ng(bar_init() == 0);
}

@miri64
Copy link
Member

miri64 commented Apr 23, 2021

What does ng stand for? I hope not next-generation, because at least the enforced evaluation of the expression sounds like a downgrade. Also keep in mind, that the POSIX spec actually specifies assert to be a macro, so I don't see much chances that assert is replaced with assert_ng at some point.

@kaspar030
Copy link
Contributor

I'm also skeptical. assert() may be somewhat ugly, but it is standardized and well understood.

@maribu
Copy link
Member Author

maribu commented Apr 23, 2021

because at least the enforced evaluation of the expression sounds like a downgrade

Well, this is my selling point for it ;-)

Because our CI always compiles without NDEBUG, things start to horribly break all over the place once NDEBUG is defined. Most often it is only an -Wunused starting to trigger, but occasionally it is because the expression in assert() has side effects the program relies upon.

What is the point in having a program showing different observable behavior in absence of failed assertions with and without NDEBUG? (And using more CPU cycles and ROM is not considered observable behavior in terms of the C abstract machine.) IMO, this only shows how little thought has gone into the standard.

I'm also skeptical. assert() may be somewhat ugly, but it is standardized and well understood.

But this provides a second macro with fixed semantics. It is not changing the semantics of assert().

@miri64
Copy link
Member

miri64 commented Apr 23, 2021

Don't we have expect() for that already?

@kaspar030
Copy link
Contributor

Don't we have expect() for that already?

expect() is a bit different: it just never compiles out. IIUC this assert_ng() is supposed to just ignore the result when NDEBUG is set.

@kaspar030
Copy link
Contributor

occasionally it is because the expression in assert() has side effects the program relies upon.

doesn't cppcheck warn on that? Anyhow, I'd rather fix those than use assert_ng().

@maribu
Copy link
Member Author

maribu commented Apr 23, 2021

doesn't cppcheck warn on that?

With --enable=style it indeed does.

Maybe we should consider to just add -Wno-unused-parameter when DEVELHELP is disabled to fix the second issue?

I will drop assert_ng() for now to at least get the ROM reduction and test in.

maribu added 2 commits April 23, 2021 12:07
Implement a large chunk of the previous preprocessor magic used to
implement `assert()` as static inline C function instead. This function
is used to implement the `assert()` macro. As result, the C compiler
has more optimization opportunities. With GCC 10.2.0, this results
in a slight reduction of ROM.
@maribu maribu changed the title core: add assert_ng() and refactor assert() core/assert: reduce use of preprocessor Apr 23, 2021
@maribu
Copy link
Member Author

maribu commented Apr 23, 2021

PR stripped of assert_ng().

@maribu
Copy link
Member Author

maribu commented Apr 23, 2021

Strange. Using my toolchain I get 460 B less for examples/gnrc_networking. Using BUILD_IN_DOCKER, I get 756 B more ROM with this PR :-/

@MrKevinWeiss MrKevinWeiss added this to the Release 2021.07 milestone Jun 22, 2021
@MrKevinWeiss MrKevinWeiss removed this from the Release 2021.07 milestone Jul 15, 2021
@maribu maribu closed this Oct 19, 2021
@maribu maribu deleted the assert branch October 19, 2021 06:41
@miri64
Copy link
Member

miri64 commented Oct 19, 2021

Can you please provide a reason why this was closed? It is not really obvious from the course of discussion here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: core Area: RIOT kernel. Handle PRs marked with this with care! Process: needs >1 ACK Integration Process: This PR requires more than one ACK Type: new feature The issue requests / The PR implemements a new feature for RIOT
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants