Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement and use MBEDTLS_STATIC_ASSERT() #7229

Merged
merged 2 commits into from
Mar 14, 2023

Conversation

tom-cosgrove-arm
Copy link
Contributor

@tom-cosgrove-arm tom-cosgrove-arm commented Mar 8, 2023

Fixes #3693

Tested the following combinations of systems/compilers/compiler flags with assert ok/expected to fail:

OpenBSD gcc 4.2.1 assert_ok [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK
OpenBSD gcc 4.2.1 assert_fails [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK

clang 10.0.1 assert_ok [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK
clang 10.0.1 assert_fails [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK

Ubuntu gcc 12.0.1 assert_ok [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK
Ubuntu gcc 12.0.1 assert_fails [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK

Ubuntu clang 15.0.7 assert_ok [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK
Ubuntu clang 15.0.7 assert_fails [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK

macOS clang 14.0.0 assert_ok [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK
macOS clang 14.0.0 assert_fails [-std=c99 [-pedantic]] -Wall -Wextra -Werror OK

Windows Visual Studio 2017 assert_ok (cmake standard build) OK
Windows Visual Studio 2017 assert_fails (cmake standard build) OK

Gatekeeper checklist

@@ -1510,10 +1510,9 @@ static int ssl_parse_client_hello(mbedtls_ssl_context *ssl)
MBEDTLS_TLS_SIG_NONE
};

#if defined(static_assert)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: since there was no #include <assert.h> at the top of this file, defined(static_assert) would always be false, so this check was never going to happen - just showing that we should have an "always-present" static assert like this

#endif
MBEDTLS_STATIC_ASSERT(
(MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE) == 0,
"One or more key attribute flag is listed as both external-only and dual-use")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annoyingly I couldn't find a way to have the macro work outside functions where it could have a ; after it, since if it expands to nothing, you end up with a stray ; that the compiler complains about

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it work to make it expand to a function declaration?

@tom-cosgrove-arm tom-cosgrove-arm added needs-review Every commit must be reviewed by at least two team members, component-platform Portability layer and build scripts needs-ci Needs to pass CI tests needs-reviewer This PR needs someone to pick it up for review size-s Estimated task size: small (~2d) priority-medium Medium priority - this can be reviewed as time permits labels Mar 8, 2023
Copy link
Contributor

@daverodgman daverodgman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but some testing would be nice. It's easy to add a test for a static assert that always passes. We'd need a new component in all.sh for a static assert that should fail to compile for certain compilers though - it would be good to have if it's not excessive effort.

Copy link
Contributor

@gilles-peskine-arm gilles-peskine-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks ok to me, but possibly incomplete.

I don't think we need tests of negative assertions on the CI. That would be a lot of work if we want to have that for multiple compilers, and not much benefit if we only do it for GCC/Clang.

#endif
MBEDTLS_STATIC_ASSERT(
(MBEDTLS_PSA_KA_MASK_EXTERNAL_ONLY & MBEDTLS_PSA_KA_MASK_DUAL_USE) == 0,
"One or more key attribute flag is listed as both external-only and dual-use")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it work to make it expand to a function declaration?

* Can't use the C11-style `defined(static_assert)` on FreeBSD, since it
* defines static_assert even with -std=c99, but then complains about it.
*/
#if defined(static_assert) && !defined(__FreeBSD__)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In C23, static_assert will no longer be a macro, it's a keyword. Should we add || __STDC_VERSION__ >= 202300L? Or just make a note to add this when C23 is finalized?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've already decided not to pre-add stuff for C23 on other PRs, so let's not add the __STDC_VERSION__ check. Not sure of the benefit of adding a TODO into the code, vs coming back once C23 is a real thing

* Can be used outside functions (but don't add a trailing ';' in that case:
* the semicolon is included here to avoid triggering -Wextra-semi when
* MBEDTLS_STATIC_ASSERT() expands to nothing).
* Can't use the C11-style `defined(static_assert)` on FreeBSD, since it
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you didn't find a way to bypass than warning 😞 . Maybe we could detect FreeBSD and use _Static_assert there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_Static_assert() is only available depending what you're building for. But yes, that could be added in a follow-up PR

#else
#define MBEDTLS_STATIC_ASSERT(expr, msg)
#endif

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also use this in tests/include/test/macros.h to replace STATIC_ASSERT_EXPR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, should be possible, but I haven't tested it. That would make an excellent follow-up PR

library/common.h Outdated
#else
#define MBEDTLS_UNUSED
#endif
#define MBEDTLS_STATIC_ASSERT2(expr, count) extern int MBEDTLS_UNUSED mbedtls_static_assert_failed ## count [2 * !!(expr) - 1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need __COUNTER__? What's the benefit over the implementation in test/macros.h?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

STATIC_ASSERT_EXPR() can only be used wherever an expression can be used, i.e. wouldn't work in some of the existing cases.

__COUNTER__ has been around in gcc for at least 10 years, so the systems without it (which this will still work on) should be fairly few.

Note I was aiming for "better (and we can build on it)" rather than "perfect"

@gilles-peskine-arm gilles-peskine-arm added needs-work and removed needs-review Every commit must be reviewed by at least two team members, needs-reviewer This PR needs someone to pick it up for review labels Mar 9, 2023
@tom-cosgrove-arm
Copy link
Contributor Author

Okay, I've updated this to more closely match development, except that it will work on FreeBSD.

Basically, just abstracts out the test to common.h and allows MBEDTLS_STATIC_ASSERT() to be used unconditionally.

We can figure out an implementation on other systems later

@daverodgman daverodgman added needs-review Every commit must be reviewed by at least two team members, and removed needs-work labels Mar 14, 2023
@tom-cosgrove-arm tom-cosgrove-arm added approved Design and code approved - may be waiting for CI or backports and removed needs-review Every commit must be reviewed by at least two team members, labels Mar 14, 2023
@daverodgman daverodgman removed the needs-ci Needs to pass CI tests label Mar 14, 2023
@daverodgman daverodgman merged commit 4a1d3be into Mbed-TLS:development Mar 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Design and code approved - may be waiting for CI or backports component-platform Portability layer and build scripts priority-medium Medium priority - this can be reviewed as time permits size-s Estimated task size: small (~2d)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

FreeBSD clang -std99 -pedantic doesn't like static_assert
4 participants