Skip to content
New issue

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

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

Already on GitHub? # to your account

core/debug: detect number of arguments #20166

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

kfessel
Copy link
Contributor

@kfessel kfessel commented Dec 11, 2023

Contribution description

this adds a number of arguments detection for the DEBUG_PRINT Macro to avoid the not very helpful "I don't print because the thread stack is to small" for cases that are cought by the printf to puts conversion (which is active starting on -O0 on gcc and llvm

Testing procedure

Debug print?

Issues/PRs references

@kfessel kfessel requested a review from kaspar030 as a code owner December 11, 2023 11:01
@github-actions github-actions bot added the Area: core Area: RIOT kernel. Handle PRs marked with this with care! label Dec 11, 2023
@kfessel kfessel requested a review from maribu December 11, 2023 11:04
@@ -44,16 +44,19 @@ extern "C" {
*/
#ifdef DEVELHELP
#include "cpu_conf.h"
#define DEBUG_PRINT(...) \
#define DEBUG_PRINT(X, ...) \
Copy link
Member

Choose a reason for hiding this comment

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

That's not standard compliant, as the C standard requires at least on argument to be present for the ....

Copy link
Contributor Author

@kfessel kfessel Dec 11, 2023

Choose a reason for hiding this comment

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

the C23 working draft has it so its probably well supported on other compilers (than GCC an clang) too

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf p178:

If there is a ... in the identifier-list in the macro definition, then the trailing arguments (if any),
including any separating comma preprocessing tokens, are merged to form a single item: the variable
arguments.

Copy link
Member

Choose a reason for hiding this comment

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

#define THREAD_EXTRA_STACKSIZE_PRINTF 42
#define NULL ((void *)0)

typedef struct thread {
    /* bla blah doesn't matter */
    unsigned stack_size;
} thread_t;

extern int printf(const char *restrict format, ...);
extern int puts(const char *s);
extern thread_t * thread_get_active(void);

#define DEBUG(X, ...) \
    do { \
        if (sizeof((const char[]){"empty"#__VA_ARGS__}) == sizeof((const char[]){"empty"}))\
            printf(X, ##__VA_ARGS__);\
        else {\
            if ((thread_get_active() == NULL) || \
                (thread_get_active()->stack_size >= \
                THREAD_EXTRA_STACKSIZE_PRINTF)) { \
                    printf(X, ##__VA_ARGS__); \
                } \
            else { \
                puts("Cannot debug, stack too small. Consider using DEBUG_PUTS()."); \
            } }\
    } while (0)

extern int a, b, c, d;

void foo(void) {
    DEBUG("Hallo\n");
    DEBUG("a = %d\n", a);
    DEBUG("a = %d, b = %d\n", a, b);
    DEBUG("a = %d, b = %d, c = %d\n", a, b, c);
}
$ clang -c -Os -std=c2x -Weverything -o test.o test.c
test.c:16:21: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   16 |             printf(X, ##__VA_ARGS__);\
      |                     ^
test.c:21:29: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   21 |                     printf(X, ##__VA_ARGS__); \
      |                             ^
test.c:16:23: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   16 |             printf(X, ##__VA_ARGS__);\
      |                       ^
test.c:21:31: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   21 |                     printf(X, ##__VA_ARGS__); \
      |                               ^
test.c:16:23: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   16 |             printf(X, ##__VA_ARGS__);\
      |                       ^
test.c:21:31: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   21 |                     printf(X, ##__VA_ARGS__); \
      |                               ^
test.c:16:23: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   16 |             printf(X, ##__VA_ARGS__);\
      |                       ^
test.c:21:31: warning: token pasting of ',' and __VA_ARGS__ is a GNU extension [-Wgnu-zero-variadic-macro-arguments]
   21 |                     printf(X, ##__VA_ARGS__); \
      |                               ^
test.c:30:6: warning: no previous prototype for function 'foo' [-Wmissing-prototypes]
   30 | void foo(void) {
      |      ^
test.c:30:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   30 | void foo(void) {
      | ^
      | static 
9 warnings generated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

<source>: .. warning: no previous prototype for function 'foo' [-Wmissing-prototypes] 

are you sure that is a applicable warning level ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

#define DEBUG(X, ...) \
    do { \
        if (sizeof((const char[]){"empty"#__VA_ARGS__}) == sizeof((const char[]){"empty"}))\
            printf(X __VA_OPT__(,) __VA_ARGS__);\
        else {\
            if ((thread_get_active() == NULL) || \
                (thread_get_active()->stack_size >= \
                THREAD_EXTRA_STACKSIZE_PRINTF)) { \
                    printf(X __VA_OPT__(,) __VA_ARGS__); \
                } \
            else { \
                puts("Cannot debug, stack too small. Consider using DEBUG_PUTS()."); \
            } }\
    } while (0)

would be the solution following the c2x draft but clang doesn't like that either :

-Os -std=c2x -Weverything

    Output of x86-64 clang 17.0.1 (Compiler #1)

<source>:32:20: warning: must specify at least one argument for '...' parameter of variadic macro [-Wgnu-zero-variadic-macro-arguments]
  32 |     DEBUG("Hallo\n");

seems like clangs warnings are not up to date

@kfessel kfessel added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Dec 11, 2023
@riot-ci
Copy link

riot-ci commented Dec 11, 2023

Murdock results

✔️ PASSED

6dd4169 core/debug: detect nargs but not for everyone

Success Failures Total Runtime
8082 0 8082 11m:27s

Artifacts

Copy link
Contributor

@kaspar030 kaspar030 left a comment

Choose a reason for hiding this comment

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

NACK.

  • using GCC specifics
  • making the macro larger instead of removing it
  • really, "detect number of arguments" in the preprocessor? RIOT markets itself as "the friendly operating system", and this definitely isn't.

@maribu
Copy link
Member

maribu commented Dec 11, 2023

Btw: I don't think we would need the bail out mechanism anymore if we would switch to picolibc. Maybe this is something that we could push instead and get rid of the bail out entirely?

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
Area: core Area: RIOT kernel. Handle PRs marked with this with care! CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants