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

Typecheck objects passed to K_POLL_EVENT_INITIALIZER #72801

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

arbrauns
Copy link
Contributor

Too many times have I accidentally passed a struct k_sem ** or similar. Thankfully modern C can help us here.

Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

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

Some notes. Seems clever.

#define K_POLL_EVENT_INITIALIZER(_event_type, _event_mode, _event_obj) \
{ \
.poller = NULL, \
.type = _event_type, \
.state = K_POLL_STATE_NOT_READY, \
.mode = _event_mode, \
.unused = 0, \
.unused = 0 + K_POLL_ASSERT_VALID_OBJECT(_event_type, _event_obj), \
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems weird to abuse this "unused" field (which is a placeholder for extra bits that would be expected to go away if we found a use for them). Can't you rework the expression to take and evaluate to the _event_obj, e.g. ".obj = VALIDATE_OBJ(_event_obj)" or whatever?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried, haven't been able to come up with any reasonable way to "get rid" of the expression resulting from the _Static_assert. I'm all ears to hear from anyone with more cursed C knowledge than me though.

Copy link
Contributor

Choose a reason for hiding this comment

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

GCC statement expressions[1] are the normal tool for that. ({ STATEMENT_A; STATEMENT_B; }) executes A and then B, but then evaluates syntactically as the result of B.

[1] An extension we do allow, because it's so pervasively supported and incredibly useful. See https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Those aren't allowed outside of function scopes, which would be a weird restriction to impose.

include/zephyr/kernel.h Outdated Show resolved Hide resolved
@@ -175,6 +175,10 @@
}
#endif

// Same as BUILD_ASSERT(), but evaluates to an expression of value 0. Useful in macros.
#define BUILD_ASSERT_EXPR(EXPR, MSG...) \
(0 * sizeof(struct { BUILD_ASSERT(EXPR, MSG); int dummy; }))
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned elsewhere, it's probably even more useful for this to take a parameter to which it will evaluate if it doesn't blow up.

@arbrauns arbrauns force-pushed the k-poll-typecheck-object branch 2 times, most recently from 077a513 to bd5fc46 Compare May 15, 2024 15:40
@npitre
Copy link
Collaborator

npitre commented May 15, 2024

You are missing K_POLL_TYPE_FIFO_DATA_AVAILABLE and have
K_POLL_TYPE_DATA_AVAILABLE twice.

I think this can be made much simpler while fully leveraging the compiler's
type checking ability, and also be C++ compatible. Consider this:

diff --git a/include/zephyr/kernel.h b/include/zephyr/kernel.h
index 32c554c159d..f4fb7765933 100644
--- a/include/zephyr/kernel.h
+++ b/include/zephyr/kernel.h
@@ -5686,14 +5686,14 @@ struct k_poll_event {
 
 	/** per-type data */
 	union {
-		void *obj;
-		struct k_poll_signal *signal;
-		struct k_sem *sem;
-		struct k_fifo *fifo;
-		struct k_queue *queue;
-		struct k_msgq *msgq;
+		void *obj, *typed_K_POLL_TYPE_IGNORE;
+		struct k_poll_signal *signal, *typed_K_POLL_TYPE_SIGNAL;
+		struct k_sem *sem, *typed_K_POLL_TYPE_SEM_AVAILABLE;
+		struct k_fifo *fifo, *typed_K_POLL_TYPE_FIFO_DATA_AVAILABLE;
+		struct k_queue *queue, *typed_K_POLL_TYPE_DATA_AVAILABLE;
+		struct k_msgq *msgq, *typed_K_POLL_TYPE_MSGQ_DATA_AVAILABLE;
 #ifdef CONFIG_PIPES
-		struct k_pipe *pipe;
+		struct k_pipe *pipe, *typed_K_POLL_TYPE_PIPE_DATA_AVAILABLE;
 #endif
 	};
 };
@@ -5706,7 +5706,7 @@ struct k_poll_event {
 	.mode = _event_mode, \
 	.unused = 0, \
 	{ \
-		.obj = _event_obj, \
+		.typed_##_event_type = _event_obj, \
 	}, \
 	}
 
@@ -5719,7 +5719,7 @@ struct k_poll_event {
 	.mode = _event_mode, \
 	.unused = 0, \
 	{ \
-		.obj = _event_obj, \
+		.typed_##_event_type = _event_obj, \
 	}, \
 	}
 

This even trips an existing test that does this:

        struct k_poll_event bad_events2[] = {
                K_POLL_EVENT_INITIALIZER(0xFU,
                                         K_POLL_MODE_NOTIFY_ONLY,
                                         &no_wait_sem),
        };

And I think that's a good thing. Initializers shouldn't be used with random
literals. The test could simply be modified to work around the initializer
in this particular case.

@cfriedt
Copy link
Member

cfriedt commented May 15, 2024

Sort of leaning toward Nico's solution and allowing the compiler to better do its job.

@arbrauns
Copy link
Contributor Author

You are missing K_POLL_TYPE_FIFO_DATA_AVAILABLE and have
K_POLL_TYPE_DATA_AVAILABLE twice.

Those are the same thing.

Anyway, I've adopted your solution, it is nicer indeed.

npitre
npitre previously approved these changes May 16, 2024
andyross
andyross previously approved these changes May 16, 2024
Copy link
Contributor

@andyross andyross left a comment

Choose a reason for hiding this comment

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

Very clean

include/zephyr/kernel.h Show resolved Hide resolved
This prevents accidentally passing the wrong pointer type (e.g. one level
of indirection too many) as the object `void *`.

Co-authored-by: Nicolas Pitre <npitre@baylibre.com>
Signed-off-by: Armin Brauns <armin.brauns@embedded-solutions.at>
@arbrauns arbrauns dismissed stale reviews from andyross and npitre via 0b9d441 May 17, 2024 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants