-
Notifications
You must be signed in to change notification settings - Fork 52
Remove assert() instances from libkmod #382
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
base: master
Are you sure you want to change the base?
Conversation
In a handful of places, we're using asserts to guard for internal API misuse. At the same time, having asserts() in a library is generally a bad idea, especially since distributions may be building with or without "-DNDEBUG". Based on code analysis, some instances are not reachable so let's remove them. Signed-off-by: Emil Velikov <[email protected]>
The function already requires that all the pointers are non-null, so add the attribute macro. Thus the compiler will give us a lovely warning when it detects a potential issue. As result we can remove the assert(), which really shouldn't exist in a shared library. Signed-off-by: Emil Velikov <[email protected]>
Handful of public facing functions check if the respective pointers are NULL initialized, while others assert() on it. Remove the latter (which is frowned upon in shared libraries) and return early in that case. Should this change yield any user-facing changes, this means they were already getting random corruption and haven't noticed it yet. Signed-off-by: Emil Velikov <[email protected]>
The only caller of module_do_install_commands() already knows the command (+ ensures it's non-null). So let's just pass it as argument, drop the duplicate kmod_module_get_install_commands() call and unreachable assert(). Signed-off-by: Emil Velikov <[email protected]>
The only caller of kmod_module_get_probe_list() already ensures that the respective arguments are not NULL. Thus we can drop the asserts(). Signed-off-by: Emil Velikov <[email protected]>
We cannot reach the assert() even though the current code-paths, do not make that abundantly clear. A follow-up commit can resolve that, but for now we can remove the assert. Signed-off-by: Emil Velikov <[email protected]>
Effectively we have two callers of the said APIs - kmod_module_new_from_lookup() and kmod_module_new_from_name_lookup(). Both of those ensure the list (pointer) is initialized, so we can drop the unreachable asserts. Signed-off-by: Emil Velikov <[email protected]>
Signed-off-by: Emil Velikov <[email protected]>
Drop the asserts and instead annotate the function as _nonnull_all_ which means we'll get a compiler warning, instead of a runtime crash should a NULL is passed to the function. Signed-off-by: Emil Velikov <[email protected]>
Remove the final assert calls from the library and the respective test. The latter being the only xfail test in the whole project and covering only one of the asserts being removed. In addition, since assert() uses abort() the code coverage of the function is completely thrown away... Which isn't great. We could reintroduce some of these checks (asserts remove here and previous commits) and/or tests, although it should probably be done differently. Having any assert() in a public/shared library is a no-go. Signed-off-by: Emil Velikov <[email protected]>
Two of the three instances are unreachable, while the last one can be replaced with proper error handling. Signed-off-by: Emil Velikov <[email protected]>
Currently we use the GNU extension _Static_assert, with a fallback for older compilers. At the same time, we require a C11 compiler, which by definition has the ISO static_assert(). Use the C11 one, remove the build-time check and diverging code path. Signed-off-by: Emil Velikov <[email protected]>
With (nearly) all assert() instances gone and the static_assert() instance properly pulling assert.h we no longer need these includes. Signed-off-by: Emil Velikov <[email protected]>
Codecov ReportAttention: Patch coverage is
🚀 New features to boost your workflow:
|
As an alternative, we could keep the In that case, we should probably check:
Although in that case, any distribution which wants to build and run tests against the same build will be stuffed. |
@@ -662,8 +655,6 @@ int kmod_elf_strip(const struct kmod_elf *elf, unsigned int flags, const void ** | |||
uint8_t *changed; | |||
int err = 0; | |||
|
|||
assert(flags & (KMOD_INSERT_FORCE_MODVERSION | KMOD_INSERT_FORCE_VERMAGIC)); |
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.
mixed feelings with these assert() removals. They were actually added for programming mistakes. Not for input errors handling. For this case, the input control is in do_init_module().
The assert here is because the function only handles KMOD_INSERT_FORCE_MODVERSION and KMOD_INSERT_FORCE_VERMAGIC. If we passed flags that doesn't contain those, it's not the end of the world: the function will continue to do its job, but it's likely wrong: it would mean we probably added another flag and forgot to add its handling in this function. By removing it we are making it silent rather than simply crash the program/test during development.
So IMO the statement "we shouldn't have asserts in a shared library" is wrong. It shouldn't be used for input control or error handling, but it's still useful to catch program programming mistakes.
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.
And true, some of them shouldn't be there and we should add the error handling, but I will need to review case by case.
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 make sense to keep some for the short run, until we get more extensive tests to cover the code-paths, or you prefer to keep them even in that case?
As a whole, it feels slightly awkward having them available (potentially reachable) in distribution builds. Perhaps they can be "enabled" with debug-messages
or another meson toggle?
Fwiw most distributions are not* be using debug-messages
these days.
- Fedora should stop using it any day now. While Gentoo/Yocto have it accessible with their modular build setups.
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.
For enabling/disabling maybe we should have this instead?
diff --git a/meson.build b/meson.build
index 5740e13..75343ed 100644
--- a/meson.build
+++ b/meson.build
@@ -7,6 +7,7 @@ project(
default_options : [
'c_std=gnu11',
'b_pie=true',
+ 'b_ndebug=if-release',
'warning_level=2',
'prefix=/usr',
'sysconfdir=/etc',
... to be merged after the wrong asserts are removed, so we still pass the testsuite tests.
Distros can also control it with -Db_ndebug=...
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.
If I'm correctly parsing the meson documentation this is the default already. The issue is that due to $reasons, at least some distributions are building with an explicit --build-type plain
.
At a glance we can easily swap the assert(static literal...) checks for
assert_cc()` as below. It seems like the better option IMHO since it's a compile-time check. What do you think?
diff --git a/shared/array.c b/shared/array.c
index 85f8955e..da40d36e 100644
--- a/shared/array.c
+++ b/shared/array.c
@@ -36,7 +36,7 @@ static void array_trim(struct array *array)
}
}
-void array_init(struct array *array, size_t step)
+void __array_init(struct array *array, size_t step)
{
array->array = NULL;
array->count = 0;
diff --git a/shared/array.h b/shared/array.h
index 8facc52d..1cdcaed0 100644
--- a/shared/array.h
+++ b/shared/array.h
@@ -13,7 +13,10 @@ struct array {
size_t step;
};
-void array_init(struct array *array, size_t step);
+void __array_init(struct array *array, size_t step);
+#define array_init(a, s) \
+ assert_cc(s > 0); \
+ __array_init(a, s);
int array_append(struct array *array, const void *element);
int array_append_unique(struct array *array, const void *element);
void array_pop(struct array *array);
As mentioned in #255, ideally we shouldn't be having
assert()
in a shared library.This series removes them, leaving the ones in depmod as-is. Most instances are unreachable and error handling is added otherwise. Where possible, call sites are annotated as
_nonnull_
so the compiler flags future issues.As a final cleanup, our
assert_cc
macro becomes a wrapper around the C11static_assert
(should we nuke our wrapper?) and header inclusions are purged.