From: Jim Cromie <[email protected]>

Add __DYNAMIC_DEBUG_CLASSMAP_CHECK to implement the following
arg-checks at compile-time:

        0 <= _base < 63
        class_names is not empty
        class_names[0] is a string
        class_names.length <= 32
        (class_names.length + _base) < 63
        dd-map-type is known value

These compile-time checks will prevent several simple misuses, issuing
obvious errors if violated.

several bad examples are ifdef DDD_MACRO_ARGCHECK qualified, into
test_dynamic_debug_submod.ko, and will fail compilation if added to
cflags.

Signed-off-by: Jim Cromie <[email protected]>
---
v5: additional test: classes.length <= 32

old-v13

reword 2 failing tests (active only when -DDD_MACRO_ARGCHECK is
passed to cc) to better identify what error is being tested against

-v12

check map-type at compile-time

make base+len(classnames) check more explicit

dyndbg-test: add more tests of compile-time CHECKs

add 3 tests of static-asserts added to 2 macros:
DYNAMIC_DEBUG_CLASSMAP_{DEFINE,USE_}

_DEFINE():
1- validates maptype,
2- validate classmap.length + base-offset < 63
_USE_():
3- validate user-offset < 63

As before, these tests fail when activated:

make KCPPFLAGS="-DDD_MACRO_ARGCHECK" lib/test_dynamic_debug_submod.o

NOTE: _USE_() cannot test classmap.length, since its a property of
the referent, not the macro itself.

dyndbg-test: verify DYNAMIC_DEBUG_CLASSMAP_USE_() compile-time CHECK

Add another failing use-case, this time to verify that _USE properly
rejects an offset > 62.  This is an incomplete test; the proper test
is: classes.length + base + offset < 63, but the macro cannot test
classes.length at compile-time.

Signed-off-by: Jim Cromie <[email protected]>
---
 include/linux/dynamic_debug.h | 16 +++++++++++++++-
 lib/test_dynamic_debug.c      | 20 +++++++++++++++++---
 2 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 17fc3a29d97b..471b9891bd83 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -197,6 +197,19 @@ struct ddebug_class_param {
  * __pr_debug_cls(22, "no such class"); compiles but is not reachable
  */
 
+#define __DYNAMIC_DEBUG_CLASSMAP_CHECK(_clnames, _base, _mapty)                
\
+       static_assert(((_base) >= 0 && (_base) < _DPRINTK_CLASS_DFLT),  \
+                     "_base must be in 0..62");                        \
+       static_assert(__DDEBUG_ARRAY_SIZE(_clnames) > 0,                        
        \
+                     "classnames array size must be > 0");             \
+       static_assert(__DDEBUG_ARRAY_SIZE(_clnames) <= 32,                      
\
+                     "classnames array size must be <= 32");           \
+       static_assert((__DDEBUG_ARRAY_SIZE(_clnames) + (_base)) < 
_DPRINTK_CLASS_DFLT, \
+                     "_base + classnames.length must be <= 62");       \
+       static_assert(((_mapty) >= DD_CLASS_TYPE_DISJOINT_BITS) &&      \
+                     ((_mapty) <= DD_CLASS_TYPE_LEVEL_NUM),            \
+                     "unknown class_map_type")
+
 /**
  * DYNAMIC_DEBUG_CLASSMAP_DEFINE - define debug classes used by a module.
  * @_var:   name of the classmap, exported for other modules coordinated use.
@@ -210,6 +223,7 @@ struct ddebug_class_param {
  */
 #define DYNAMIC_DEBUG_CLASSMAP_DEFINE(_var, _mapty, _base, ...)                
\
        static const char *_var##_classnames[] = { __VA_ARGS__ };       \
+       __DYNAMIC_DEBUG_CLASSMAP_CHECK(_var##_classnames, (_base), (_mapty)); \
        extern struct ddebug_class_map _var;                            \
        struct ddebug_class_map __aligned(8) __used                     \
                __section("__dyndbg_class_maps") _var = {               \
@@ -217,7 +231,7 @@ struct ddebug_class_param {
                .mod_name = DDEBUG_MODNAME,                             \
                .base = (_base),                                        \
                .map_type = (_mapty),                                   \
-               .length = ARRAY_SIZE(_var##_classnames),                \
+               .length = __DDEBUG_ARRAY_SIZE(_var##_classnames),       \
                .class_names = _var##_classnames,                       \
        };                                                              \
        EXPORT_SYMBOL(_var)
diff --git a/lib/test_dynamic_debug.c b/lib/test_dynamic_debug.c
index 3a69cc3cae6d..01ce07001d4c 100644
--- a/lib/test_dynamic_debug.c
+++ b/lib/test_dynamic_debug.c
@@ -148,12 +148,26 @@ DYNAMIC_DEBUG_CLASSMAP_USE_(map_level_num, 7);
 
 enum cat_level_offset { Vu1 = V1 + 7, Vu2, Vu3, Vu4, Vu5, Vu6, Vu7 };
 
-#endif
-
+#if defined(DD_MACRO_ARGCHECK)
 /*
- * now add the sysfs-params
+ * Exersize compile-time arg-checks in DYNAMIC_DEBUG_CLASSMAP_DEFINE.
+ * These will break compilation.
  */
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_base_neg, 0, -1, "NEGATIVE_BASE_ARG");
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_base_big, 0, 100, "TOOBIG_BASE_ARG");
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_str_type, 0, 0, 1 /* not a string */);
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_emptyclass, 0, 0 /* ,empty */);
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_maptype, 3, 10, "no such type");
+DYNAMIC_DEBUG_CLASSMAP_DEFINE(fail_base_len, 0, 60,
+                             "base", "plus", "classes", "length", "too-big");
+DYNAMIC_DEBUG_CLASSMAP_USE_(fail_offset_big, 100);
+#endif /* DD_MACRO_ARGCHECK */
+
+#endif /* TEST_DYNAMIC_DEBUG_SUBMOD */
 
+/*
+ * now add the sysfs-params to both sub/super-mods
+ */
 DYNAMIC_DEBUG_CLASSMAP_PARAM(disjoint_bits, p);
 DYNAMIC_DEBUG_CLASSMAP_PARAM(level_num, p);
 

-- 
2.55.0


Reply via email to