-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Implement and use MBEDTLS_STATIC_ASSERT() #7229
Conversation
Fixes Mbed-TLS#3693 Signed-off-by: Tom Cosgrove <[email protected]>
@@ -1510,10 +1510,9 @@ static int ssl_parse_client_hello(mbedtls_ssl_context *ssl) | |||
MBEDTLS_TLS_SIG_NONE | |||
}; | |||
|
|||
#if defined(static_assert) |
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this 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.
There was a problem hiding this 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") |
There was a problem hiding this comment.
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__) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 | ||
|
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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]; |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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"
Signed-off-by: Tom Cosgrove <[email protected]>
Okay, I've updated this to more closely match Basically, just abstracts out the test to We can figure out an implementation on other systems later |
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