All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] kunit: Rework kunit_resource allocation policy
@ 2022-03-19  5:56 David Gow
  2022-03-22  1:57 ` Daniel Latypov
  0 siblings, 1 reply; 8+ messages in thread
From: David Gow @ 2022-03-19  5:56 UTC (permalink / raw)
  To: Brendan Higgins, Daniel Latypov, Shuah Khan
  Cc: David Gow, kunit-dev, linux-kselftest, linux-kernel

KUnit's test-managed resources can be created in two ways:
- Using the kunit_add_resource() family of functions, which accept a
  struct kunit_resource pointer, typically allocated statically or on
  the stack during the test.
- Using the kunit_alloc_resource() family of functions, which allocate a
  struct kunit_resource using kzalloc() behind the scenes.

Both of these families of functions accept a 'free' function to be
called when the resource is finally disposed of.

At present, KUnit will kfree() the resource if this 'free' function is
specified, and will not if it is NULL. However, this can lead
kunit_alloc_resource() to leak memory (if no 'free' function is passed
in), or kunit_add_resource() to incorrectly kfree() memory which was
allocated by some other means (on the stack, as part of a larger
allocation, etc), if a 'free' function is provided.

Instead, always kfree() if the resource was allocated with
kunit_alloc_resource(), and never kfree() if it was passed into
kunit_add_resource() by the user. (If the user of kunit_add_resource()
wishes the resource be kfree()ed, they can call kfree() on the resource
from within the 'free' function.

This is implemented by adding a 'should_free' member to
struct kunit_resource and setting it appropriately. To facilitate this,
the various resource add/alloc functions have been refactored somewhat,
making them all call a __kunit_add_resource() helper after setting the
'should_free' member appropriately. In the process, all other functions
have been made static inline functions.

Signed-off-by: David Gow <davidgow@google.com>
---
 include/kunit/test.h | 135 +++++++++++++++++++++++++++++++++++--------
 lib/kunit/test.c     |  65 +++------------------
 2 files changed, 120 insertions(+), 80 deletions(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index 00b9ff7783ab..5a3aacbadda2 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -36,11 +36,14 @@ typedef void (*kunit_resource_free_t)(struct kunit_resource *);
  * struct kunit_resource - represents a *test managed resource*
  * @data: for the user to store arbitrary data.
  * @name: optional name
- * @free: a user supplied function to free the resource. Populated by
- * kunit_resource_alloc().
+ * @free: a user supplied function to free the resource.
  *
  * Represents a *test managed resource*, a resource which will automatically be
- * cleaned up at the end of a test case.
+ * cleaned up at the end of a test case. This cleanup is performed by the 'free'
+ * function. The resource itself is allocated with kmalloc() and freed with
+ * kfree() if created with kunit_alloc_{,and_get_}resource(), otherwise it must
+ * be freed by the user, typically with the 'free' function, or automatically if
+ * it's allocated on the stack.
  *
  * Resources are reference counted so if a resource is retrieved via
  * kunit_alloc_and_get_resource() or kunit_find_resource(), we need
@@ -97,6 +100,7 @@ struct kunit_resource {
 	/* private: internal use only. */
 	struct kref refcount;
 	struct list_head node;
+	bool should_free;
 };
 
 struct kunit;
@@ -385,16 +389,6 @@ static inline int kunit_run_all_tests(void)
 
 enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite);
 
-/*
- * Like kunit_alloc_resource() below, but returns the struct kunit_resource
- * object that contains the allocation. This is mostly for testing purposes.
- */
-struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test,
-						    kunit_resource_init_t init,
-						    kunit_resource_free_t free,
-						    gfp_t internal_gfp,
-						    void *context);
-
 /**
  * kunit_get_resource() - Hold resource for use.  Should not need to be used
  *			  by most users as we automatically get resources
@@ -416,10 +410,14 @@ static inline void kunit_release_resource(struct kref *kref)
 						  refcount);
 
 	/* If free function is defined, resource was dynamically allocated. */
-	if (res->free) {
+	if (res->free)
 		res->free(res);
+
+	/* 'res' is valid here, as if should_free is set, res->free may not free
+	 * 'res' itself, just res->data
+	 */
+	if (res->should_free)
 		kfree(res);
-	}
 }
 
 /**
@@ -440,7 +438,9 @@ static inline void kunit_put_resource(struct kunit_resource *res)
 }
 
 /**
- * kunit_add_resource() - Add a *test managed resource*.
+ * __kunit_add_resource() - Internal helper to add a resource.
+ *
+ * res->should_free is not initialised.
  * @test: The test context object.
  * @init: a user-supplied function to initialize the result (if needed).  If
  *        none is supplied, the resource data value is simply set to @data.
@@ -449,12 +449,34 @@ static inline void kunit_put_resource(struct kunit_resource *res)
  * @res: The resource.
  * @data: value to pass to init function or set in resource data field.
  */
-int kunit_add_resource(struct kunit *test,
+int __kunit_add_resource(struct kunit *test,
 		       kunit_resource_init_t init,
 		       kunit_resource_free_t free,
 		       struct kunit_resource *res,
 		       void *data);
 
+/**
+ * kunit_add_resource() - Add a *test managed resource*.
+ * @test: The test context object.
+ * @init: a user-supplied function to initialize the result (if needed).  If
+ *        none is supplied, the resource data value is simply set to @data.
+ *	  If an init function is supplied, @data is passed to it instead.
+ * @free: a user-supplied function to free the resource (if needed).
+ * @res: The resource.
+ * @data: value to pass to init function or set in resource data field.
+ */
+static inline int kunit_add_resource(struct kunit *test,
+				     kunit_resource_init_t init,
+				     kunit_resource_free_t free,
+				     struct kunit_resource *res,
+				     void *data)
+{
+	res->should_free = false;
+	return __kunit_add_resource(test, init, free, res, data);
+}
+
+static inline struct kunit_resource *
+kunit_find_named_resource(struct kunit *test, const char *name);
 /**
  * kunit_add_named_resource() - Add a named *test managed resource*.
  * @test: The test context object.
@@ -464,18 +486,84 @@ int kunit_add_resource(struct kunit *test,
  * @name: name to be set for resource.
  * @data: value to pass to init function or set in resource data field.
  */
-int kunit_add_named_resource(struct kunit *test,
+static inline int kunit_add_named_resource(struct kunit *test,
+					   kunit_resource_init_t init,
+					   kunit_resource_free_t free,
+					   struct kunit_resource *res,
+					   const char *name,
+					   void *data)
+{
+	struct kunit_resource *existing;
+
+	if (!name)
+		return -EINVAL;
+
+	existing = kunit_find_named_resource(test, name);
+	if (existing) {
+		kunit_put_resource(existing);
+		return -EEXIST;
+	}
+
+	res->name = name;
+	res->should_free = false;
+
+	return __kunit_add_resource(test, init, free, res, data);
+}
+
+/**
+ * kunit_alloc_and_get_resource() - Allocates and returns a *test managed resource*.
+ * @test: The test context object.
+ * @init: a user supplied function to initialize the resource.
+ * @free: a user supplied function to free the resource (if needed).
+ * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL
+ * @context: for the user to pass in arbitrary data to the init function.
+ *
+ * Allocates a *test managed resource*, a resource which will automatically be
+ * cleaned up at the end of a test case. See &struct kunit_resource for an
+ * example.
+ *
+ * This is effectively identical to kunit_alloc_resource, but returns the
+ * struct kunit_resource pointer, not just the 'data' pointer. It therefore
+ * also increments the resource's refcount, so kunit_put_resource() should be
+ * called when you've finished with it.
+ *
+ * Note: KUnit needs to allocate memory for a kunit_resource object. You must
+ * specify an @internal_gfp that is compatible with the use context of your
+ * resource.
+ */
+static inline struct kunit_resource *
+kunit_alloc_and_get_resource(struct kunit *test,
 			     kunit_resource_init_t init,
 			     kunit_resource_free_t free,
-			     struct kunit_resource *res,
-			     const char *name,
-			     void *data);
+			     gfp_t internal_gfp,
+			     void *context)
+{
+	struct kunit_resource *res;
+	int ret;
+
+	res = kzalloc(sizeof(*res), internal_gfp);
+	if (!res)
+		return NULL;
+
+	res->should_free = true;
+
+	ret = __kunit_add_resource(test, init, free, res, context);
+	if (!ret) {
+		/*
+		 * bump refcount for get; kunit_resource_put() should be called
+		 * when done.
+		 */
+		kunit_get_resource(res);
+		return res;
+	}
+	return NULL;
+}
 
 /**
  * kunit_alloc_resource() - Allocates a *test managed resource*.
  * @test: The test context object.
  * @init: a user supplied function to initialize the resource.
- * @free: a user supplied function to free the resource.
+ * @free: a user supplied function to free the resource (if needed).
  * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL
  * @context: for the user to pass in arbitrary data to the init function.
  *
@@ -499,7 +587,8 @@ static inline void *kunit_alloc_resource(struct kunit *test,
 	if (!res)
 		return NULL;
 
-	if (!kunit_add_resource(test, init, free, res, context))
+	res->should_free = true;
+	if (!__kunit_add_resource(test, init, free, res, context))
 		return res->data;
 
 	return NULL;
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 3bca3bf5c15b..b4f10329abb8 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -596,18 +596,19 @@ EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);
  * Used for static resources and when a kunit_resource * has been created by
  * kunit_alloc_resource().  When an init function is supplied, @data is passed
  * into the init function; otherwise, we simply set the resource data field to
- * the data value passed in.
+ * the data value passed in. Doesn't initialize res->should_free.
  */
-int kunit_add_resource(struct kunit *test,
-		       kunit_resource_init_t init,
-		       kunit_resource_free_t free,
-		       struct kunit_resource *res,
-		       void *data)
+int __kunit_add_resource(struct kunit *test,
+			 kunit_resource_init_t init,
+			 kunit_resource_free_t free,
+			 struct kunit_resource *res,
+			 void *data)
 {
 	int ret = 0;
 	unsigned long flags;
 
 	res->free = free;
+	res->should_free = false;
 	kref_init(&res->refcount);
 
 	if (init) {
@@ -625,57 +626,7 @@ int kunit_add_resource(struct kunit *test,
 
 	return ret;
 }
-EXPORT_SYMBOL_GPL(kunit_add_resource);
-
-int kunit_add_named_resource(struct kunit *test,
-			     kunit_resource_init_t init,
-			     kunit_resource_free_t free,
-			     struct kunit_resource *res,
-			     const char *name,
-			     void *data)
-{
-	struct kunit_resource *existing;
-
-	if (!name)
-		return -EINVAL;
-
-	existing = kunit_find_named_resource(test, name);
-	if (existing) {
-		kunit_put_resource(existing);
-		return -EEXIST;
-	}
-
-	res->name = name;
-
-	return kunit_add_resource(test, init, free, res, data);
-}
-EXPORT_SYMBOL_GPL(kunit_add_named_resource);
-
-struct kunit_resource *kunit_alloc_and_get_resource(struct kunit *test,
-						    kunit_resource_init_t init,
-						    kunit_resource_free_t free,
-						    gfp_t internal_gfp,
-						    void *data)
-{
-	struct kunit_resource *res;
-	int ret;
-
-	res = kzalloc(sizeof(*res), internal_gfp);
-	if (!res)
-		return NULL;
-
-	ret = kunit_add_resource(test, init, free, res, data);
-	if (!ret) {
-		/*
-		 * bump refcount for get; kunit_resource_put() should be called
-		 * when done.
-		 */
-		kunit_get_resource(res);
-		return res;
-	}
-	return NULL;
-}
-EXPORT_SYMBOL_GPL(kunit_alloc_and_get_resource);
+EXPORT_SYMBOL_GPL(__kunit_add_resource);
 
 void kunit_remove_resource(struct kunit *test, struct kunit_resource *res)
 {
-- 
2.35.1.894.gb6a874cedc-goog


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] kunit: Rework kunit_resource allocation policy
  2022-03-19  5:56 [PATCH] kunit: Rework kunit_resource allocation policy David Gow
@ 2022-03-22  1:57 ` Daniel Latypov
  2022-03-22  4:10   ` David Gow
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Latypov @ 2022-03-22  1:57 UTC (permalink / raw)
  To: David Gow
  Cc: Brendan Higgins, Shuah Khan, kunit-dev, linux-kselftest, linux-kernel

On Sat, Mar 19, 2022 at 12:56 AM David Gow <davidgow@google.com> wrote:
>
> KUnit's test-managed resources can be created in two ways:
> - Using the kunit_add_resource() family of functions, which accept a
>   struct kunit_resource pointer, typically allocated statically or on
>   the stack during the test.
> - Using the kunit_alloc_resource() family of functions, which allocate a
>   struct kunit_resource using kzalloc() behind the scenes.
>
> Both of these families of functions accept a 'free' function to be
> called when the resource is finally disposed of.
>
> At present, KUnit will kfree() the resource if this 'free' function is
> specified, and will not if it is NULL. However, this can lead
> kunit_alloc_resource() to leak memory (if no 'free' function is passed
> in), or kunit_add_resource() to incorrectly kfree() memory which was
> allocated by some other means (on the stack, as part of a larger
> allocation, etc), if a 'free' function is provided.

Trying it with this:

static void noop_free_resource(struct kunit_resource *) {}

struct kunit_resource global_res;

static void example_simple_test(struct kunit *test)
{
        kunit_add_resource(test, NULL, noop_free_resource, &global_res, test);
}

Running then with
$ run_kunit --kunitconfig=lib/kunit --arch=x86_64
--build_dir=kunit_x86/ --kconfig_add=CONFIG_KASAN=y

Before:
BUG: KASAN: double-free or invalid-free in kunit_cleanup+0x51/0xb0

After:
Passes

>
> Instead, always kfree() if the resource was allocated with
> kunit_alloc_resource(), and never kfree() if it was passed into
> kunit_add_resource() by the user. (If the user of kunit_add_resource()
> wishes the resource be kfree()ed, they can call kfree() on the resource
> from within the 'free' function.
>
> This is implemented by adding a 'should_free' member to

nit: would `should_kfree` be a bit better?
`should_free` almost sounds like "should we invoke res->free" (as
nonsensical as that might be)

> struct kunit_resource and setting it appropriately. To facilitate this,
> the various resource add/alloc functions have been refactored somewhat,
> making them all call a __kunit_add_resource() helper after setting the
> 'should_free' member appropriately. In the process, all other functions
> have been made static inline functions.
>
> Signed-off-by: David Gow <davidgow@google.com>

Tested-by: Daniel Latypov <dlatypov@google.com>


> ---
>  include/kunit/test.h | 135 +++++++++++++++++++++++++++++++++++--------
>  lib/kunit/test.c     |  65 +++------------------
>  2 files changed, 120 insertions(+), 80 deletions(-)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index 00b9ff7783ab..5a3aacbadda2 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -36,11 +36,14 @@ typedef void (*kunit_resource_free_t)(struct kunit_resource *);
>   * struct kunit_resource - represents a *test managed resource*
>   * @data: for the user to store arbitrary data.
>   * @name: optional name
> - * @free: a user supplied function to free the resource. Populated by
> - * kunit_resource_alloc().
> + * @free: a user supplied function to free the resource.
>   *
>   * Represents a *test managed resource*, a resource which will automatically be
> - * cleaned up at the end of a test case.
> + * cleaned up at the end of a test case. This cleanup is performed by the 'free'
> + * function. The resource itself is allocated with kmalloc() and freed with
> + * kfree() if created with kunit_alloc_{,and_get_}resource(), otherwise it must
> + * be freed by the user, typically with the 'free' function, or automatically if
> + * it's allocated on the stack.

I'm not a fan of this complexity, but I'm not sure if we have a way
around it, esp. w/ stack-allocated data.

Perhaps this would be a bit easier to read if we tweaked it a bit like:
"freed with kfree() if allocated by KUnit (via kunit_alloc..."

Maybe we can drop the "or automatically, if it's allocated on the
stack" as well.

A bigger way to simplify: perhaps we should get rid of
kunit_alloc_and_get_resource() first?
It's only used in KUnit's tests for itself.
They could instead use kunit_alloc_resource() +
kunit_find_resource(test, kunit_resource_instance_match, data).
We could even define the helper with the same name in kunit-test.c
(the only place it's used).

Alternatively, we could make it an internal helper and define
kunit_alloc_resource() as

void *kunit_alloc_resource(...)
{
   struct kunit_resource *res = _kunit_alloc_and_get_resource(...)
   if (res) return res->data;
   return NULL;
}

?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kunit: Rework kunit_resource allocation policy
  2022-03-22  1:57 ` Daniel Latypov
@ 2022-03-22  4:10   ` David Gow
  2022-03-22  7:06     ` Daniel Latypov
  0 siblings, 1 reply; 8+ messages in thread
From: David Gow @ 2022-03-22  4:10 UTC (permalink / raw)
  To: Daniel Latypov
  Cc: Brendan Higgins, Shuah Khan, KUnit Development,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List

[-- Attachment #1: Type: text/plain, Size: 7123 bytes --]

On Tue, Mar 22, 2022 at 9:57 AM 'Daniel Latypov' via KUnit Development
<kunit-dev@googlegroups.com> wrote:
>
> On Sat, Mar 19, 2022 at 12:56 AM David Gow <davidgow@google.com> wrote:
> >
> > KUnit's test-managed resources can be created in two ways:
> > - Using the kunit_add_resource() family of functions, which accept a
> >   struct kunit_resource pointer, typically allocated statically or on
> >   the stack during the test.
> > - Using the kunit_alloc_resource() family of functions, which allocate a
> >   struct kunit_resource using kzalloc() behind the scenes.
> >
> > Both of these families of functions accept a 'free' function to be
> > called when the resource is finally disposed of.
> >
> > At present, KUnit will kfree() the resource if this 'free' function is
> > specified, and will not if it is NULL. However, this can lead
> > kunit_alloc_resource() to leak memory (if no 'free' function is passed
> > in), or kunit_add_resource() to incorrectly kfree() memory which was
> > allocated by some other means (on the stack, as part of a larger
> > allocation, etc), if a 'free' function is provided.
>
> Trying it with this:
>
> static void noop_free_resource(struct kunit_resource *) {}
>
> struct kunit_resource global_res;
>
> static void example_simple_test(struct kunit *test)
> {
>         kunit_add_resource(test, NULL, noop_free_resource, &global_res, test);
> }
>
> Running then with
> $ run_kunit --kunitconfig=lib/kunit --arch=x86_64
> --build_dir=kunit_x86/ --kconfig_add=CONFIG_KASAN=y
>
> Before:
> BUG: KASAN: double-free or invalid-free in kunit_cleanup+0x51/0xb0
>
> After:
> Passes
>

Phew! :-)
I'm glad it works.

> >
> > Instead, always kfree() if the resource was allocated with
> > kunit_alloc_resource(), and never kfree() if it was passed into
> > kunit_add_resource() by the user. (If the user of kunit_add_resource()
> > wishes the resource be kfree()ed, they can call kfree() on the resource
> > from within the 'free' function.
> >
> > This is implemented by adding a 'should_free' member to
>
> nit: would `should_kfree` be a bit better?
> `should_free` almost sounds like "should we invoke res->free" (as
> nonsensical as that might be)
>

I think I had it as should_kfree at some point. I agree it's a little
clearer. I'll rename it back.

The other option I considered was to have a "flags" member, of which
SHOULD_KFREE could be one. Though I eventually decided to leave that
until we needed another flag.

> > struct kunit_resource and setting it appropriately. To facilitate this,
> > the various resource add/alloc functions have been refactored somewhat,
> > making them all call a __kunit_add_resource() helper after setting the
> > 'should_free' member appropriately. In the process, all other functions
> > have been made static inline functions.
> >
> > Signed-off-by: David Gow <davidgow@google.com>
>
> Tested-by: Daniel Latypov <dlatypov@google.com>
>
>
> > ---
> >  include/kunit/test.h | 135 +++++++++++++++++++++++++++++++++++--------
> >  lib/kunit/test.c     |  65 +++------------------
> >  2 files changed, 120 insertions(+), 80 deletions(-)
> >
> > diff --git a/include/kunit/test.h b/include/kunit/test.h
> > index 00b9ff7783ab..5a3aacbadda2 100644
> > --- a/include/kunit/test.h
> > +++ b/include/kunit/test.h
> > @@ -36,11 +36,14 @@ typedef void (*kunit_resource_free_t)(struct kunit_resource *);
> >   * struct kunit_resource - represents a *test managed resource*
> >   * @data: for the user to store arbitrary data.
> >   * @name: optional name
> > - * @free: a user supplied function to free the resource. Populated by
> > - * kunit_resource_alloc().
> > + * @free: a user supplied function to free the resource.
> >   *
> >   * Represents a *test managed resource*, a resource which will automatically be
> > - * cleaned up at the end of a test case.
> > + * cleaned up at the end of a test case. This cleanup is performed by the 'free'
> > + * function. The resource itself is allocated with kmalloc() and freed with
> > + * kfree() if created with kunit_alloc_{,and_get_}resource(), otherwise it must
> > + * be freed by the user, typically with the 'free' function, or automatically if
> > + * it's allocated on the stack.
>
> I'm not a fan of this complexity, but I'm not sure if we have a way
> around it, esp. w/ stack-allocated data.
>
The other option is to make all resources allocated with
kunit_alloc_resource() require a non-NULL 'free' function which calls
kfree() itself. This is much simpler on the KUnit side, but does put
some of that burden on the user (and may prevent a free() function
from being shared between allocated and non-allocated resources).

> Perhaps this would be a bit easier to read if we tweaked it a bit like:
> "freed with kfree() if allocated by KUnit (via kunit_alloc..."
>
> Maybe we can drop the "or automatically, if it's allocated on the
> stack" as well.

Yeah: I'm not 100% happy with that wording. I wanted to make it clear
that there are cases where no automatic freeing is needed, but I agree
it's really just making things more confusing.
>
> A bigger way to simplify: perhaps we should get rid of
> kunit_alloc_and_get_resource() first?
> It's only used in KUnit's tests for itself.
> They could instead use kunit_alloc_resource() +
> kunit_find_resource(test, kunit_resource_instance_match, data).
> We could even define the helper with the same name in kunit-test.c
> (the only place it's used).
>
> Alternatively, we could make it an internal helper and define
> kunit_alloc_resource() as
>
> void *kunit_alloc_resource(...)
> {
>    struct kunit_resource *res = _kunit_alloc_and_get_resource(...)
>    if (res) return res->data;
>    return NULL;
> }
>
> ?
>

I was thinking about this a bit this morning, and I think we should do
the opposite: get rid of kunit_alloc_resource() and leave only
kunit_alloc_and_get_resource().
Then, split the resource system basically in two:
- The system for managing "findable" resources, whose main purpose is
for cases like the KASAN integration and the stub stuff where main
goal is tying some named bit of data to a test, and reference counting
it so it can safely be retrieved and used throughout the kernel if
need be.
- The simpler "free this on test exit" system, which could be as
simple as a kunit_defer(func, context) function built on top of the
former. This wouldn't need detailed tracking of reference counts, etc,

(tl;dr: I think that kunit_alloc_resource() is broken, refcount-wise,
if we're trying to implement the first kind of system, but useful for
the second, and this is quite confusing. So kunit_alloc_resource()
probably shouldn't be used alongside kunit_find_resource(), as there
could be a potential race condition. Now, this shouldn't happen in
practice, as most tests are single threaded and none are doing fancy
things with kunit_remove_resource(), but
kunit_alloc_and_get_resource() should be safer, as you're not playing
with a resource you don't have a reference to according to the
refcount.)

That's a more complicated refactor and redesign of the resources
system, though, so I'd rather fix this first.

Cheers,
-- David

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4003 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kunit: Rework kunit_resource allocation policy
  2022-03-22  4:10   ` David Gow
@ 2022-03-22  7:06     ` Daniel Latypov
  2022-03-23  7:22       ` Brendan Higgins
  0 siblings, 1 reply; 8+ messages in thread
From: Daniel Latypov @ 2022-03-22  7:06 UTC (permalink / raw)
  To: David Gow
  Cc: Brendan Higgins, Shuah Khan, KUnit Development,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List

On Mon, Mar 21, 2022 at 11:10 PM David Gow <davidgow@google.com> wrote:
>
> On Tue, Mar 22, 2022 at 9:57 AM 'Daniel Latypov' via KUnit Development
> <kunit-dev@googlegroups.com> wrote:
> >
> > On Sat, Mar 19, 2022 at 12:56 AM David Gow <davidgow@google.com> wrote:
> > >
> > > KUnit's test-managed resources can be created in two ways:
> > > - Using the kunit_add_resource() family of functions, which accept a
> > >   struct kunit_resource pointer, typically allocated statically or on
> > >   the stack during the test.
> > > - Using the kunit_alloc_resource() family of functions, which allocate a
> > >   struct kunit_resource using kzalloc() behind the scenes.
> > >
> > > Both of these families of functions accept a 'free' function to be
> > > called when the resource is finally disposed of.
> > >
> > > At present, KUnit will kfree() the resource if this 'free' function is
> > > specified, and will not if it is NULL. However, this can lead
> > > kunit_alloc_resource() to leak memory (if no 'free' function is passed
> > > in), or kunit_add_resource() to incorrectly kfree() memory which was
> > > allocated by some other means (on the stack, as part of a larger
> > > allocation, etc), if a 'free' function is provided.
> >
> > Trying it with this:
> >
> > static void noop_free_resource(struct kunit_resource *) {}
> >
> > struct kunit_resource global_res;
> >
> > static void example_simple_test(struct kunit *test)
> > {
> >         kunit_add_resource(test, NULL, noop_free_resource, &global_res, test);
> > }
> >
> > Running then with
> > $ run_kunit --kunitconfig=lib/kunit --arch=x86_64
> > --build_dir=kunit_x86/ --kconfig_add=CONFIG_KASAN=y
> >
> > Before:
> > BUG: KASAN: double-free or invalid-free in kunit_cleanup+0x51/0xb0
> >
> > After:
> > Passes
> >
>
> Phew! :-)
> I'm glad it works.
>
> > >
> > > Instead, always kfree() if the resource was allocated with
> > > kunit_alloc_resource(), and never kfree() if it was passed into
> > > kunit_add_resource() by the user. (If the user of kunit_add_resource()
> > > wishes the resource be kfree()ed, they can call kfree() on the resource
> > > from within the 'free' function.
> > >
> > > This is implemented by adding a 'should_free' member to
> >
> > nit: would `should_kfree` be a bit better?
> > `should_free` almost sounds like "should we invoke res->free" (as
> > nonsensical as that might be)
> >
>
> I think I had it as should_kfree at some point. I agree it's a little
> clearer. I'll rename it back.
>
> The other option I considered was to have a "flags" member, of which
> SHOULD_KFREE could be one. Though I eventually decided to leave that
> until we needed another flag.
>
> > > struct kunit_resource and setting it appropriately. To facilitate this,
> > > the various resource add/alloc functions have been refactored somewhat,
> > > making them all call a __kunit_add_resource() helper after setting the
> > > 'should_free' member appropriately. In the process, all other functions
> > > have been made static inline functions.
> > >
> > > Signed-off-by: David Gow <davidgow@google.com>
> >
> > Tested-by: Daniel Latypov <dlatypov@google.com>
> >
> >
> > > ---
> > >  include/kunit/test.h | 135 +++++++++++++++++++++++++++++++++++--------
> > >  lib/kunit/test.c     |  65 +++------------------
> > >  2 files changed, 120 insertions(+), 80 deletions(-)
> > >
> > > diff --git a/include/kunit/test.h b/include/kunit/test.h
> > > index 00b9ff7783ab..5a3aacbadda2 100644
> > > --- a/include/kunit/test.h
> > > +++ b/include/kunit/test.h
> > > @@ -36,11 +36,14 @@ typedef void (*kunit_resource_free_t)(struct kunit_resource *);
> > >   * struct kunit_resource - represents a *test managed resource*
> > >   * @data: for the user to store arbitrary data.
> > >   * @name: optional name
> > > - * @free: a user supplied function to free the resource. Populated by
> > > - * kunit_resource_alloc().
> > > + * @free: a user supplied function to free the resource.
> > >   *
> > >   * Represents a *test managed resource*, a resource which will automatically be
> > > - * cleaned up at the end of a test case.
> > > + * cleaned up at the end of a test case. This cleanup is performed by the 'free'
> > > + * function. The resource itself is allocated with kmalloc() and freed with
> > > + * kfree() if created with kunit_alloc_{,and_get_}resource(), otherwise it must
> > > + * be freed by the user, typically with the 'free' function, or automatically if
> > > + * it's allocated on the stack.
> >
> > I'm not a fan of this complexity, but I'm not sure if we have a way
> > around it, esp. w/ stack-allocated data.
> >
> The other option is to make all resources allocated with
> kunit_alloc_resource() require a non-NULL 'free' function which calls
> kfree() itself. This is much simpler on the KUnit side, but does put
> some of that burden on the user (and may prevent a free() function
> from being shared between allocated and non-allocated resources).

Overall, I'm ambivalent.

To be honest, I'm not sure how real the user burden would be (it's
basically 0 right now).

This would only add about 6 more lines to add a kfree version:
static void free_stack_resource(struct kunit_resource *res) { ... }

static void free_heap_resource(struct kunit_resource *res)
{
   free_stack_resource(res);
   kfree(res);
}

So far, this function is only ever used w/ non-NULL free functions
(even in the under-review stubbing patches).
So now would be the time to make such a change.

But I'm slightly against such a change.
It slightly complicates the "resources as storage" usecase in favor of
simplifying the "resources as memory wranglers".
Maybe it'd be fine if we added a helper they could use, e.g.
  void kunit_resource_default_free(struct kunit_resource *res) { kfree(res); }
but it

>
> > Perhaps this would be a bit easier to read if we tweaked it a bit like:
> > "freed with kfree() if allocated by KUnit (via kunit_alloc..."
> >
> > Maybe we can drop the "or automatically, if it's allocated on the
> > stack" as well.
>
> Yeah: I'm not 100% happy with that wording. I wanted to make it clear
> that there are cases where no automatic freeing is needed, but I agree
> it's really just making things more confusing.
> >
> > A bigger way to simplify: perhaps we should get rid of
> > kunit_alloc_and_get_resource() first?
> > It's only used in KUnit's tests for itself.
> > They could instead use kunit_alloc_resource() +
> > kunit_find_resource(test, kunit_resource_instance_match, data).
> > We could even define the helper with the same name in kunit-test.c
> > (the only place it's used).
> >
> > Alternatively, we could make it an internal helper and define
> > kunit_alloc_resource() as
> >
> > void *kunit_alloc_resource(...)
> > {
> >    struct kunit_resource *res = _kunit_alloc_and_get_resource(...)
> >    if (res) return res->data;
> >    return NULL;
> > }
> >
> > ?
> >
>
> I was thinking about this a bit this morning, and I think we should do
> the opposite: get rid of kunit_alloc_resource() and leave only
> kunit_alloc_and_get_resource().
> Then, split the resource system basically in two:
> - The system for managing "findable" resources, whose main purpose is
> for cases like the KASAN integration and the stub stuff where main
> goal is tying some named bit of data to a test, and reference counting
> it so it can safely be retrieved and used throughout the kernel if
> need be.
> - The simpler "free this on test exit" system, which could be as
> simple as a kunit_defer(func, context) function built on top of the
> former. This wouldn't need detailed tracking of reference counts, etc,

Agree that there's two distinct usecases here.
One wants a replacement for global variables (which thus need
"finding") and the other just wants to ensure some function like
kfree() gets called.

The latter ~never need to get "found" (e.g. kunit_kmalloc() users).
The one exception: when people use kunit_kfree() to free things early,
which requires us to "find" these resources we otherwise wouldn't care
about.

So I don't know how we can split the API unless we get rid of kunit_kfree().
Its presence means kunit_kmalloc() and friends need refcounting.

Can we drop it? Maybe.
Looking at the uses of kunit_kfree(), they're all internal to kunit except one.

   111  static void
ne_misc_dev_test_merge_phys_contig_memory_regions(struct kunit *test)
   112  {
...
   117          phys_contig_mem_regions.regions = kunit_kcalloc(test,
MAX_PHYS_REGIONS,
   118
sizeof(*phys_contig_mem_regions.regions),
   119                                                          GFP_KERNEL);
...
   140
   141          kunit_kfree(test, phys_contig_mem_regions.regions);
   142  }

Hmm, that looks redundant since it's right before the end of the test case.
We can drop that call, I think.

But I think kunit_kfree() can serve a purpose.
E.g. for short-lived allocations where assertions are used.
  buf = kunit_kzalloc(test, sizeof(*buf), GFP_KERNEL);
  KUNIT_ASSERT_EQ(test, do_stuff(buf), 0);
  KUNIT_EXPECT_EQ(test, <something about buf>);
  kunit_kfree(buf);
  // do more stuff

Sure we can drop kunit_kfree() and have `buf` stick around longer than needed.
Or we could rewrite it like
  buf = kzalloc(sizeof(*buf), GFP_KERNEL);
  if (do_stuff(buf)) {
    KUNIT_FAIL(test, "do_stuff() failed");
  } else {
     KUNIT_EXPECT_EQ(test, <something about buf>);
  }
  kfree(buf);
 but I think the kunit_kfree() code is cleaner.

>
> (tl;dr: I think that kunit_alloc_resource() is broken, refcount-wise,
> if we're trying to implement the first kind of system, but useful for
> the second, and this is quite confusing. So kunit_alloc_resource()
> probably shouldn't be used alongside kunit_find_resource(), as there
> could be a potential race condition. Now, this shouldn't happen in
> practice, as most tests are single threaded and none are doing fancy
> things with kunit_remove_resource(), but
> kunit_alloc_and_get_resource() should be safer, as you're not playing
> with a resource you don't have a reference to according to the
> refcount.)
>
> That's a more complicated refactor and redesign of the resources
> system, though, so I'd rather fix this first.
>
> Cheers,
> -- David

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kunit: Rework kunit_resource allocation policy
  2022-03-22  7:06     ` Daniel Latypov
@ 2022-03-23  7:22       ` Brendan Higgins
  2022-03-23 19:20         ` Daniel Latypov
  0 siblings, 1 reply; 8+ messages in thread
From: Brendan Higgins @ 2022-03-23  7:22 UTC (permalink / raw)
  To: Daniel Latypov
  Cc: David Gow, Shuah Khan, KUnit Development,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List

On Tue, Mar 22, 2022 at 3:06 AM Daniel Latypov <dlatypov@google.com> wrote:
>
> On Mon, Mar 21, 2022 at 11:10 PM David Gow <davidgow@google.com> wrote:
> >
> > On Tue, Mar 22, 2022 at 9:57 AM 'Daniel Latypov' via KUnit Development
> > <kunit-dev@googlegroups.com> wrote:
> > >
> > > On Sat, Mar 19, 2022 at 12:56 AM David Gow <davidgow@google.com> wrote:
> > > >
> > > > KUnit's test-managed resources can be created in two ways:
> > > > - Using the kunit_add_resource() family of functions, which accept a
> > > >   struct kunit_resource pointer, typically allocated statically or on
> > > >   the stack during the test.
> > > > - Using the kunit_alloc_resource() family of functions, which allocate a
> > > >   struct kunit_resource using kzalloc() behind the scenes.
> > > >
> > > > Both of these families of functions accept a 'free' function to be
> > > > called when the resource is finally disposed of.
> > > >
> > > > At present, KUnit will kfree() the resource if this 'free' function is
> > > > specified, and will not if it is NULL. However, this can lead
> > > > kunit_alloc_resource() to leak memory (if no 'free' function is passed
> > > > in), or kunit_add_resource() to incorrectly kfree() memory which was
> > > > allocated by some other means (on the stack, as part of a larger
> > > > allocation, etc), if a 'free' function is provided.
> > >
> > > Trying it with this:
> > >
> > > static void noop_free_resource(struct kunit_resource *) {}
> > >
> > > struct kunit_resource global_res;
> > >
> > > static void example_simple_test(struct kunit *test)
> > > {
> > >         kunit_add_resource(test, NULL, noop_free_resource, &global_res, test);
> > > }
> > >
> > > Running then with
> > > $ run_kunit --kunitconfig=lib/kunit --arch=x86_64
> > > --build_dir=kunit_x86/ --kconfig_add=CONFIG_KASAN=y
> > >
> > > Before:
> > > BUG: KASAN: double-free or invalid-free in kunit_cleanup+0x51/0xb0
> > >
> > > After:
> > > Passes
> > >
> >
> > Phew! :-)
> > I'm glad it works.
> >
> > > >
> > > > Instead, always kfree() if the resource was allocated with
> > > > kunit_alloc_resource(), and never kfree() if it was passed into
> > > > kunit_add_resource() by the user. (If the user of kunit_add_resource()
> > > > wishes the resource be kfree()ed, they can call kfree() on the resource
> > > > from within the 'free' function.
> > > >
> > > > This is implemented by adding a 'should_free' member to
> > >
> > > nit: would `should_kfree` be a bit better?
> > > `should_free` almost sounds like "should we invoke res->free" (as
> > > nonsensical as that might be)
> > >
> >
> > I think I had it as should_kfree at some point. I agree it's a little
> > clearer. I'll rename it back.
> >
> > The other option I considered was to have a "flags" member, of which
> > SHOULD_KFREE could be one. Though I eventually decided to leave that
> > until we needed another flag.
> >
> > > > struct kunit_resource and setting it appropriately. To facilitate this,
> > > > the various resource add/alloc functions have been refactored somewhat,
> > > > making them all call a __kunit_add_resource() helper after setting the
> > > > 'should_free' member appropriately. In the process, all other functions
> > > > have been made static inline functions.
> > > >
> > > > Signed-off-by: David Gow <davidgow@google.com>
> > >
> > > Tested-by: Daniel Latypov <dlatypov@google.com>
> > >
> > >
> > > > ---
> > > >  include/kunit/test.h | 135 +++++++++++++++++++++++++++++++++++--------
> > > >  lib/kunit/test.c     |  65 +++------------------
> > > >  2 files changed, 120 insertions(+), 80 deletions(-)
> > > >
> > > > diff --git a/include/kunit/test.h b/include/kunit/test.h
> > > > index 00b9ff7783ab..5a3aacbadda2 100644
> > > > --- a/include/kunit/test.h
> > > > +++ b/include/kunit/test.h
> > > > @@ -36,11 +36,14 @@ typedef void (*kunit_resource_free_t)(struct kunit_resource *);
> > > >   * struct kunit_resource - represents a *test managed resource*
> > > >   * @data: for the user to store arbitrary data.
> > > >   * @name: optional name
> > > > - * @free: a user supplied function to free the resource. Populated by
> > > > - * kunit_resource_alloc().
> > > > + * @free: a user supplied function to free the resource.
> > > >   *
> > > >   * Represents a *test managed resource*, a resource which will automatically be
> > > > - * cleaned up at the end of a test case.
> > > > + * cleaned up at the end of a test case. This cleanup is performed by the 'free'
> > > > + * function. The resource itself is allocated with kmalloc() and freed with
> > > > + * kfree() if created with kunit_alloc_{,and_get_}resource(), otherwise it must
> > > > + * be freed by the user, typically with the 'free' function, or automatically if
> > > > + * it's allocated on the stack.
> > >
> > > I'm not a fan of this complexity, but I'm not sure if we have a way
> > > around it, esp. w/ stack-allocated data.
> > >
> > The other option is to make all resources allocated with
> > kunit_alloc_resource() require a non-NULL 'free' function which calls
> > kfree() itself. This is much simpler on the KUnit side, but does put
> > some of that burden on the user (and may prevent a free() function
> > from being shared between allocated and non-allocated resources).
>
> Overall, I'm ambivalent.
>
> To be honest, I'm not sure how real the user burden would be (it's
> basically 0 right now).
>
> This would only add about 6 more lines to add a kfree version:
> static void free_stack_resource(struct kunit_resource *res) { ... }
>
> static void free_heap_resource(struct kunit_resource *res)
> {
>    free_stack_resource(res);
>    kfree(res);
> }
>
> So far, this function is only ever used w/ non-NULL free functions
> (even in the under-review stubbing patches).
> So now would be the time to make such a change.
>
> But I'm slightly against such a change.
> It slightly complicates the "resources as storage" usecase in favor of
> simplifying the "resources as memory wranglers".
> Maybe it'd be fine if we added a helper they could use, e.g.
>   void kunit_resource_default_free(struct kunit_resource *res) { kfree(res); }
> but it

I agree. I am not a fan of requiring a non-null free function. I think
the solution is better captured by splitting up the resource API, like
you suggest elsewhere as a long term solution.

In the short term, I like what you did here with the should_kfree.

> > > Perhaps this would be a bit easier to read if we tweaked it a bit like:
> > > "freed with kfree() if allocated by KUnit (via kunit_alloc..."
> > >
> > > Maybe we can drop the "or automatically, if it's allocated on the
> > > stack" as well.
> >
> > Yeah: I'm not 100% happy with that wording. I wanted to make it clear
> > that there are cases where no automatic freeing is needed, but I agree
> > it's really just making things more confusing.
> > >
> > > A bigger way to simplify: perhaps we should get rid of
> > > kunit_alloc_and_get_resource() first?
> > > It's only used in KUnit's tests for itself.
> > > They could instead use kunit_alloc_resource() +
> > > kunit_find_resource(test, kunit_resource_instance_match, data).
> > > We could even define the helper with the same name in kunit-test.c
> > > (the only place it's used).
> > >
> > > Alternatively, we could make it an internal helper and define
> > > kunit_alloc_resource() as
> > >
> > > void *kunit_alloc_resource(...)
> > > {
> > >    struct kunit_resource *res = _kunit_alloc_and_get_resource(...)
> > >    if (res) return res->data;
> > >    return NULL;
> > > }
> > >
> > > ?
> > >
> >
> > I was thinking about this a bit this morning, and I think we should do
> > the opposite: get rid of kunit_alloc_resource() and leave only
> > kunit_alloc_and_get_resource().
> > Then, split the resource system basically in two:
> > - The system for managing "findable" resources, whose main purpose is
> > for cases like the KASAN integration and the stub stuff where main
> > goal is tying some named bit of data to a test, and reference counting
> > it so it can safely be retrieved and used throughout the kernel if
> > need be.
> > - The simpler "free this on test exit" system, which could be as
> > simple as a kunit_defer(func, context) function built on top of the
> > former. This wouldn't need detailed tracking of reference counts, etc,
>
> Agree that there's two distinct usecases here.
> One wants a replacement for global variables (which thus need
> "finding") and the other just wants to ensure some function like
> kfree() gets called.

Agreed.

> The latter ~never need to get "found" (e.g. kunit_kmalloc() users).
> The one exception: when people use kunit_kfree() to free things early,
> which requires us to "find" these resources we otherwise wouldn't care
> about.
>
> So I don't know how we can split the API unless we get rid of kunit_kfree().
> Its presence means kunit_kmalloc() and friends need refcounting.

Do we need to choose between dropping kunit_kfree() and refcounting? I
think this is semantically different from other findable resources,
and I think it fairly obviously entails the complexity of using it.

> Can we drop it? Maybe.
> Looking at the uses of kunit_kfree(), they're all internal to kunit except one.
>
>    111  static void
> ne_misc_dev_test_merge_phys_contig_memory_regions(struct kunit *test)
>    112  {
> ...
>    117          phys_contig_mem_regions.regions = kunit_kcalloc(test,
> MAX_PHYS_REGIONS,
>    118
> sizeof(*phys_contig_mem_regions.regions),
>    119                                                          GFP_KERNEL);
> ...
>    140
>    141          kunit_kfree(test, phys_contig_mem_regions.regions);
>    142  }
>
> Hmm, that looks redundant since it's right before the end of the test case.
> We can drop that call, I think.
>
> But I think kunit_kfree() can serve a purpose.
> E.g. for short-lived allocations where assertions are used.
>   buf = kunit_kzalloc(test, sizeof(*buf), GFP_KERNEL);
>   KUNIT_ASSERT_EQ(test, do_stuff(buf), 0);
>   KUNIT_EXPECT_EQ(test, <something about buf>);
>   kunit_kfree(buf);
>   // do more stuff
>
> Sure we can drop kunit_kfree() and have `buf` stick around longer than needed.
> Or we could rewrite it like
>   buf = kzalloc(sizeof(*buf), GFP_KERNEL);
>   if (do_stuff(buf)) {
>     KUNIT_FAIL(test, "do_stuff() failed");
>   } else {
>      KUNIT_EXPECT_EQ(test, <something about buf>);
>   }
>   kfree(buf);
>  but I think the kunit_kfree() code is cleaner.
>
> >
> > (tl;dr: I think that kunit_alloc_resource() is broken, refcount-wise,
> > if we're trying to implement the first kind of system, but useful for
> > the second, and this is quite confusing. So kunit_alloc_resource()
> > probably shouldn't be used alongside kunit_find_resource(), as there
> > could be a potential race condition. Now, this shouldn't happen in
> > practice, as most tests are single threaded and none are doing fancy
> > things with kunit_remove_resource(), but
> > kunit_alloc_and_get_resource() should be safer, as you're not playing
> > with a resource you don't have a reference to according to the
> > refcount.)
> >
> > That's a more complicated refactor and redesign of the resources
> > system, though, so I'd rather fix this first.
> >
> > Cheers,
> > -- David

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kunit: Rework kunit_resource allocation policy
  2022-03-23  7:22       ` Brendan Higgins
@ 2022-03-23 19:20         ` Daniel Latypov
  0 siblings, 0 replies; 8+ messages in thread
From: Daniel Latypov @ 2022-03-23 19:20 UTC (permalink / raw)
  To: Brendan Higgins
  Cc: David Gow, Shuah Khan, KUnit Development,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List

On Wed, Mar 23, 2022 at 2:22 AM Brendan Higgins
<brendanhiggins@google.com> wrote:
>

<snip>

>
> > The latter ~never need to get "found" (e.g. kunit_kmalloc() users).
> > The one exception: when people use kunit_kfree() to free things early,
> > which requires us to "find" these resources we otherwise wouldn't care
> > about.
> >
> > So I don't know how we can split the API unless we get rid of kunit_kfree().
> > Its presence means kunit_kmalloc() and friends need refcounting.
>
> Do we need to choose between dropping kunit_kfree() and refcounting? I
> think this is semantically different from other findable resources,
> and I think it fairly obviously entails the complexity of using it.

Yes, they're different.
We could do something different and just have a atomic bool "is_freed"
for the kunit_kmalloc() style resources.

But is it worth it?

Currently kunit_kfree() is defined as
697:void kunit_kfree(struct kunit *test, const void *ptr)
698-{
699-    struct kunit_resource *res;
700-
701-    res = kunit_find_resource(test, kunit_resource_instance_match,
702-                              (void *)ptr);
703-
704-    /*
705-     * Removing the resource from the list of resources drops the
706-     * reference count to 1; the final put will trigger the free.
707-     */
708-    kunit_remove_resource(test, res);
709-
710-    kunit_put_resource(res);
711-
712-}

i.e. the overhead of using a refcount is that we need to call
kunit_put_resource() bc we called kunit_find_resource().
IMO, this less semantic overhead than adding a different mechanism
specifically for kunit_kfree().

Tangent:
Huh, it segfaults if you call kunit_kfree() on a non-kunit allocated ptr.
res == NULL on 701 in that case, but kunit_remove_resource() doesn't
guard against that.
It also happens if you call kunit_free() twice.

That's analogous to how kfree() works, so I guess that's fine.
A difference though is
  kfree(NULL); // is fine
  kunit_free(test, NULL); // segfaults, res == NULL above

But thinking on it more, someone could register a resource w/ data == NULL.
I.e. a named resource which just acts as a flag via presence/absence.
kunit_kfree(test, NULL) would the most recent such resource though.

Should we do the trick/hack where we check the free function first in
kunit_kfree() to avoid such confusion?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kunit: Rework kunit_resource allocation policy
@ 2022-03-20 15:52 kernel test robot
  0 siblings, 0 replies; 8+ messages in thread
From: kernel test robot @ 2022-03-20 15:52 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 14042 bytes --]

CC: llvm(a)lists.linux.dev
CC: kbuild-all(a)lists.01.org
BCC: lkp(a)intel.com
In-Reply-To: <20220319055600.3471875-1-davidgow@google.com>
References: <20220319055600.3471875-1-davidgow@google.com>
TO: David Gow <davidgow@google.com>
TO: Brendan Higgins <brendanhiggins@google.com>
TO: Daniel Latypov <dlatypov@google.com>
TO: Shuah Khan <skhan@linuxfoundation.org>
CC: David Gow <davidgow@google.com>
CC: kunit-dev(a)googlegroups.com
CC: linux-kselftest(a)vger.kernel.org
CC: linux-kernel(a)vger.kernel.org

Hi David,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc8 next-20220318]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/David-Gow/kunit-Rework-kunit_resource-allocation-policy/20220319-135701
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 34e047aa16c0123bbae8e2f6df33e5ecc1f56601
:::::: branch date: 34 hours ago
:::::: commit date: 34 hours ago
config: riscv-randconfig-c006-20220320 (https://download.01.org/0day-ci/archive/20220320/202203202343.fPluqjlg-lkp(a)intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 217f267efe3082438e698e2f08566b9df8c530fa)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install riscv cross compiling tool for clang build
        # apt-get install binutils-riscv64-linux-gnu
        # https://github.com/0day-ci/linux/commit/1e8a349a7a1c6a46c24b09755471e053d1f04c8d
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review David-Gow/kunit-Rework-kunit_resource-allocation-policy/20220319-135701
        git checkout 1e8a349a7a1c6a46c24b09755471e053d1f04c8d
        # save the config file to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=riscv clang-analyzer 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


clang-analyzer warnings: (new ones prefixed by >>)
           ^
   include/linux/compiler_types.h:334:2: note: expanded from macro '_compiletime_assert'
           __compiletime_assert(condition, msg, prefix, suffix)
           ^
   include/linux/compiler_types.h:326:3: note: expanded from macro '__compiletime_assert'
                   if (!(condition))                                       \
                   ^
   include/linux/sched.h:1628:2: note: Loop condition is false.  Exiting loop
           BUILD_BUG_ON_NOT_POWER_OF_2(TASK_REPORT_MAX);
           ^
   include/linux/build_bug.h:23:2: note: expanded from macro 'BUILD_BUG_ON_NOT_POWER_OF_2'
           BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
           ^
   include/linux/build_bug.h:50:2: note: expanded from macro 'BUILD_BUG_ON'
           BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
           ^
   include/linux/build_bug.h:39:37: note: expanded from macro 'BUILD_BUG_ON_MSG'
   #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
                                       ^
   include/linux/compiler_types.h:346:2: note: expanded from macro 'compiletime_assert'
           _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
           ^
   include/linux/compiler_types.h:334:2: note: expanded from macro '_compiletime_assert'
           __compiletime_assert(condition, msg, prefix, suffix)
           ^
   include/linux/compiler_types.h:318:2: note: expanded from macro '__compiletime_assert'
           do {                                                            \
           ^
   include/linux/sched.h:1630:6: note: Assuming the condition is false
           if (tsk_state == TASK_IDLE)
               ^~~~~~~~~~~~~~~~~~~~~~
   include/linux/sched.h:1630:2: note: Taking false branch
           if (tsk_state == TASK_IDLE)
           ^
   include/linux/sched.h:1633:9: note: Calling 'fls'
           return fls(state);
                  ^~~~~~~~~~
   include/asm-generic/bitops/fls.h:15:2: note: 'r' initialized to 32
           int r = 32;
           ^~~~~
   include/asm-generic/bitops/fls.h:17:6: note: Assuming 'x' is not equal to 0, which participates in a condition later
           if (!x)
               ^~
   include/asm-generic/bitops/fls.h:17:2: note: Taking false branch
           if (!x)
           ^
   include/asm-generic/bitops/fls.h:19:6: note: Assuming the condition is false
           if (!(x & 0xffff0000u)) {
               ^~~~~~~~~~~~~~~~~~
   include/asm-generic/bitops/fls.h:19:2: note: Taking false branch
           if (!(x & 0xffff0000u)) {
           ^
   include/asm-generic/bitops/fls.h:23:6: note: Assuming the condition is false
           if (!(x & 0xff000000u)) {
               ^~~~~~~~~~~~~~~~~~
   include/asm-generic/bitops/fls.h:23:2: note: Taking false branch
           if (!(x & 0xff000000u)) {
           ^
   include/asm-generic/bitops/fls.h:27:6: note: Assuming the condition is false
           if (!(x & 0xf0000000u)) {
               ^~~~~~~~~~~~~~~~~~
   include/asm-generic/bitops/fls.h:27:2: note: Taking false branch
           if (!(x & 0xf0000000u)) {
           ^
   include/asm-generic/bitops/fls.h:31:6: note: Assuming the condition is false
           if (!(x & 0xc0000000u)) {
               ^~~~~~~~~~~~~~~~~~
   include/asm-generic/bitops/fls.h:31:2: note: Taking false branch
           if (!(x & 0xc0000000u)) {
           ^
   include/asm-generic/bitops/fls.h:35:6: note: Assuming the condition is false
           if (!(x & 0x80000000u)) {
               ^~~~~~~~~~~~~~~~~~
   include/asm-generic/bitops/fls.h:35:2: note: Taking false branch
           if (!(x & 0x80000000u)) {
           ^
   include/asm-generic/bitops/fls.h:39:2: note: Returning the value 32 (loaded from 'r')
           return r;
           ^~~~~~~~
   include/linux/sched.h:1633:9: note: Returning from 'fls'
           return fls(state);
                  ^~~~~~~~~~
   include/linux/sched.h:1633:2: note: Returning the value 32
           return fls(state);
           ^~~~~~~~~~~~~~~~~
   fs/proc/array.c:142:26: note: Returning from 'task_state_index'
           return task_state_array[task_state_index(tsk)];
                                   ^~~~~~~~~~~~~~~~~~~~~
   fs/proc/array.c:142:2: note: Undefined or garbage value returned to caller
           return task_state_array[task_state_index(tsk)];
           ^      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   Suppressed 2 warnings (2 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   2 warnings generated.
   Suppressed 2 warnings (2 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   2 warnings generated.
   Suppressed 2 warnings (2 in non-user code).
   Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
   5 warnings generated.
>> include/kunit/test.h:412:6: warning: Use of memory after it is freed [clang-analyzer-unix.Malloc]
           if (res->free)
               ^
   lib/kunit/test.c:285:6: note: Assuming 'pass' is false
           if (pass)
               ^~~~
   lib/kunit/test.c:285:2: note: Taking false branch
           if (pass)
           ^
   lib/kunit/test.c:293:2: note: Calling 'kunit_fail'
           kunit_fail(test, assert);
           ^~~~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/test.c:250:6: note: Assuming 'stream' is non-null
           if (!stream) {
               ^~~~~~~
   lib/kunit/test.c:250:2: note: Taking false branch
           if (!stream) {
           ^
   lib/kunit/test.c:260:2: note: Calling 'kunit_print_string_stream'
           kunit_print_string_stream(test, stream);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/test.c:226:6: note: Assuming the condition is false
           if (string_stream_is_empty(stream))
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/test.c:226:2: note: Taking false branch
           if (string_stream_is_empty(stream))
           ^
   lib/kunit/test.c:230:6: note: Assuming 'buf' is non-null
           if (!buf) {
               ^~~~
   lib/kunit/test.c:230:2: note: Taking false branch
           if (!buf) {
           ^
   lib/kunit/test.c:238:3: note: Loop condition is false.  Exiting loop
                   kunit_err(test, "%s", buf);
                   ^
   include/kunit/test.h:850:2: note: expanded from macro 'kunit_err'
           kunit_printk(KERN_ERR, test, fmt, ##__VA_ARGS__)
           ^
   include/kunit/test.h:815:2: note: expanded from macro 'kunit_printk'
           kunit_log(lvl, test, KUNIT_SUBTEST_INDENT "# %s: " fmt,         \
           ^
   include/kunit/test.h:809:3: note: expanded from macro 'kunit_log'
                   printk(lvl fmt, ##__VA_ARGS__);                         \
                   ^
   include/linux/printk.h:446:26: note: expanded from macro 'printk'
   #define printk(fmt, ...) printk_index_wrap(_printk, fmt, ##__VA_ARGS__)
                            ^
   include/linux/printk.h:417:3: note: expanded from macro 'printk_index_wrap'
                   __printk_index_emit(_fmt, NULL, NULL);                  \
                   ^
   include/linux/printk.h:392:34: note: expanded from macro '__printk_index_emit'
   #define __printk_index_emit(...) do {} while (0)
                                    ^
   lib/kunit/test.c:238:3: note: Loop condition is false.  Exiting loop
                   kunit_err(test, "%s", buf);
                   ^
   include/kunit/test.h:850:2: note: expanded from macro 'kunit_err'
           kunit_printk(KERN_ERR, test, fmt, ##__VA_ARGS__)
           ^
   include/kunit/test.h:815:2: note: expanded from macro 'kunit_printk'
           kunit_log(lvl, test, KUNIT_SUBTEST_INDENT "# %s: " fmt,         \
           ^
   include/kunit/test.h:808:2: note: expanded from macro 'kunit_log'
           do {                                                            \
           ^
   lib/kunit/test.c:239:3: note: Calling 'kunit_kfree'
                   kunit_kfree(test, buf);
                   ^~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/test.c:708:2: note: Calling 'kunit_remove_resource'
           kunit_remove_resource(test, res);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/test.c:634:2: note: Loop condition is false.  Exiting loop
           spin_lock_irqsave(&test->lock, flags);
           ^
   include/linux/spinlock.h:379:2: note: expanded from macro 'spin_lock_irqsave'
           raw_spin_lock_irqsave(spinlock_check(lock), flags);     \
           ^
   include/linux/spinlock.h:240:2: note: expanded from macro 'raw_spin_lock_irqsave'
           do {                                            \
           ^
   lib/kunit/test.c:634:2: note: Loop condition is false.  Exiting loop
           spin_lock_irqsave(&test->lock, flags);
           ^
   include/linux/spinlock.h:377:43: note: expanded from macro 'spin_lock_irqsave'
   #define spin_lock_irqsave(lock, flags)                          \
                                                                   ^
   lib/kunit/test.c:637:2: note: Calling 'kunit_put_resource'
           kunit_put_resource(res);
           ^~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:436:2: note: Calling 'kref_put'
           kref_put(&res->refcount, kunit_release_resource);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/kref.h:64:6: note: Assuming the condition is true
           if (refcount_dec_and_test(&kref->refcount)) {
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/kref.h:64:2: note: Taking true branch
           if (refcount_dec_and_test(&kref->refcount)) {
           ^
   include/linux/kref.h:65:3: note: Calling 'kunit_release_resource'
                   release(kref);

vim +412 include/kunit/test.h

d4cdd146d0db90 Alan Maguire 2020-05-29  401  
d4cdd146d0db90 Alan Maguire 2020-05-29  402  /*
d4cdd146d0db90 Alan Maguire 2020-05-29  403   * Called when refcount reaches zero via kunit_put_resources();
d4cdd146d0db90 Alan Maguire 2020-05-29  404   * should not be called directly.
d4cdd146d0db90 Alan Maguire 2020-05-29  405   */
d4cdd146d0db90 Alan Maguire 2020-05-29  406  static inline void kunit_release_resource(struct kref *kref)
d4cdd146d0db90 Alan Maguire 2020-05-29  407  {
d4cdd146d0db90 Alan Maguire 2020-05-29  408  	struct kunit_resource *res = container_of(kref, struct kunit_resource,
d4cdd146d0db90 Alan Maguire 2020-05-29  409  						  refcount);
d4cdd146d0db90 Alan Maguire 2020-05-29  410  
d4cdd146d0db90 Alan Maguire 2020-05-29  411  	/* If free function is defined, resource was dynamically allocated. */
1e8a349a7a1c6a David Gow    2022-03-19 @412  	if (res->free)
d4cdd146d0db90 Alan Maguire 2020-05-29  413  		res->free(res);
1e8a349a7a1c6a David Gow    2022-03-19  414  
1e8a349a7a1c6a David Gow    2022-03-19  415  	/* 'res' is valid here, as if should_free is set, res->free may not free
1e8a349a7a1c6a David Gow    2022-03-19  416  	 * 'res' itself, just res->data
1e8a349a7a1c6a David Gow    2022-03-19  417  	 */
1e8a349a7a1c6a David Gow    2022-03-19  418  	if (res->should_free)
d4cdd146d0db90 Alan Maguire 2020-05-29  419  		kfree(res);
d4cdd146d0db90 Alan Maguire 2020-05-29  420  }
d4cdd146d0db90 Alan Maguire 2020-05-29  421  

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] kunit: Rework kunit_resource allocation policy
@ 2022-03-20  5:03 kernel test robot
  0 siblings, 0 replies; 8+ messages in thread
From: kernel test robot @ 2022-03-20  5:03 UTC (permalink / raw)
  To: kbuild

[-- Attachment #1: Type: text/plain, Size: 17309 bytes --]

CC: llvm(a)lists.linux.dev
CC: kbuild-all(a)lists.01.org
BCC: lkp(a)intel.com
In-Reply-To: <20220319055600.3471875-1-davidgow@google.com>
References: <20220319055600.3471875-1-davidgow@google.com>
TO: David Gow <davidgow@google.com>
TO: Brendan Higgins <brendanhiggins@google.com>
TO: Daniel Latypov <dlatypov@google.com>
TO: Shuah Khan <skhan@linuxfoundation.org>
CC: David Gow <davidgow@google.com>
CC: kunit-dev(a)googlegroups.com
CC: linux-kselftest(a)vger.kernel.org
CC: linux-kernel(a)vger.kernel.org

Hi David,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc8 next-20220318]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/David-Gow/kunit-Rework-kunit_resource-allocation-policy/20220319-135701
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 34e047aa16c0123bbae8e2f6df33e5ecc1f56601
:::::: branch date: 23 hours ago
:::::: commit date: 23 hours ago
config: arm-randconfig-c002-20220318 (https://download.01.org/0day-ci/archive/20220320/202203201240.n4S4nyak-lkp(a)intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project a6e70e4056dff962ec634c5bd4f2f4105a0bef71)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm cross compiling tool for clang build
        # apt-get install binutils-arm-linux-gnueabi
        # https://github.com/0day-ci/linux/commit/1e8a349a7a1c6a46c24b09755471e053d1f04c8d
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review David-Gow/kunit-Rework-kunit_resource-allocation-policy/20220319-135701
        git checkout 1e8a349a7a1c6a46c24b09755471e053d1f04c8d
        # save the config file to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=arm clang-analyzer 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>


clang-analyzer warnings: (new ones prefixed by >>)
           ^
   include/kunit/test.h:418:6: note: Assuming field 'should_free' is true
           if (res->should_free)
               ^~~~~~~~~~~~~~~~
   include/kunit/test.h:418:2: note: Taking true branch
           if (res->should_free)
           ^
   include/kunit/test.h:419:3: note: Argument to kfree() is the address of a local stack variable, which is not memory allocated by malloc()
                   kfree(res);
                   ^     ~~~
   lib/kunit/kunit-test.c:187:9: warning: Use of memory after it is freed [clang-analyzer-unix.Malloc]
                                                     res->data));
                                                     ^
   include/kunit/test.h:1719:47: note: expanded from macro 'KUNIT_ASSERT_FALSE'
           KUNIT_FALSE_ASSERTION(test, KUNIT_ASSERTION, condition)
                                                        ^~~~~~~~~
   include/kunit/test.h:938:47: note: expanded from macro 'KUNIT_FALSE_ASSERTION'
           KUNIT_FALSE_MSG_ASSERTION(test, assert_type, condition, NULL)
                                                        ^~~~~~~~~
   include/kunit/test.h:932:10: note: expanded from macro 'KUNIT_FALSE_MSG_ASSERTION'
                                 condition,                                       \
                                 ^~~~~~~~~
   include/kunit/test.h:909:7: note: expanded from macro 'KUNIT_UNARY_ASSERTION'
                           !!(condition) == !!expected_true,                      \
                              ^~~~~~~~~
   include/kunit/test.h:871:7: note: expanded from macro 'KUNIT_ASSERTION'
                              pass,                                               \
                              ^~~~
   lib/kunit/kunit-test.c:175:31: note: Calling 'kunit_alloc_and_get_resource'
           struct kunit_resource *res = kunit_alloc_and_get_resource(
                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:544:6: note: Assuming 'res' is non-null
           if (!res)
               ^~~~
   include/kunit/test.h:544:2: note: Taking false branch
           if (!res)
           ^
   include/kunit/test.h:550:6: note: Assuming 'ret' is 0
           if (!ret) {
               ^~~~
   include/kunit/test.h:550:2: note: Taking true branch
           if (!ret) {
           ^
   lib/kunit/kunit-test.c:175:31: note: Returning from 'kunit_alloc_and_get_resource'
           struct kunit_resource *res = kunit_alloc_and_get_resource(
                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/kunit-test.c:182:2: note: Calling 'kunit_put_resource'
           kunit_put_resource(res);
           ^~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:436:2: note: Calling 'kref_put'
           kref_put(&res->refcount, kunit_release_resource);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/kref.h:64:2: note: Taking true branch
           if (refcount_dec_and_test(&kref->refcount)) {
           ^
   include/linux/kref.h:65:3: note: Calling 'kunit_release_resource'
                   release(kref);
                   ^~~~~~~~~~~~~
   include/kunit/test.h:412:6: note: Assuming field 'free' is null
           if (res->free)
               ^~~~~~~~~
   include/kunit/test.h:412:2: note: Taking false branch
           if (res->free)
           ^
   include/kunit/test.h:418:6: note: Assuming field 'should_free' is true
           if (res->should_free)
               ^~~~~~~~~~~~~~~~
   include/kunit/test.h:418:2: note: Taking true branch
           if (res->should_free)
           ^
   include/kunit/test.h:419:3: note: Memory is released
                   kfree(res);
                   ^~~~~~~~~~
   include/linux/kref.h:65:3: note: Returning; memory was released
                   release(kref);
                   ^~~~~~~~~~~~~
   include/kunit/test.h:436:2: note: Returning; memory was released
           kref_put(&res->refcount, kunit_release_resource);
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/kunit-test.c:182:2: note: Returning; memory was released via 1st parameter
           kunit_put_resource(res);
           ^~~~~~~~~~~~~~~~~~~~~~~
   lib/kunit/kunit-test.c:187:9: note: Use of memory after it is freed
                                                     res->data));
                                                     ^
   include/kunit/test.h:1719:47: note: expanded from macro 'KUNIT_ASSERT_FALSE'
           KUNIT_FALSE_ASSERTION(test, KUNIT_ASSERTION, condition)
                                                        ^~~~~~~~~
   include/kunit/test.h:938:47: note: expanded from macro 'KUNIT_FALSE_ASSERTION'
           KUNIT_FALSE_MSG_ASSERTION(test, assert_type, condition, NULL)
                                                        ^~~~~~~~~
   include/kunit/test.h:932:10: note: expanded from macro 'KUNIT_FALSE_MSG_ASSERTION'
                                 condition,                                       \
                                 ^~~~~~~~~
   include/kunit/test.h:909:7: note: expanded from macro 'KUNIT_UNARY_ASSERTION'
                           !!(condition) == !!expected_true,                      \
                              ^~~~~~~~~
   include/kunit/test.h:871:7: note: expanded from macro 'KUNIT_ASSERTION'
                              pass,                                               \
                              ^~~~
>> lib/kunit/kunit-test.c:337:2: warning: Assigned value is garbage or undefined [clang-analyzer-core.uninitialized.Assign]
           KUNIT_EXPECT_PTR_EQ(test, res1.data, (void *)&ctx);
           ^
   include/kunit/test.h:1473:2: note: expanded from macro 'KUNIT_EXPECT_PTR_EQ'
           KUNIT_BINARY_PTR_EQ_ASSERTION(test,                                    \
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:1110:2: note: expanded from macro 'KUNIT_BINARY_PTR_EQ_ASSERTION'
           KUNIT_BINARY_PTR_EQ_MSG_ASSERTION(test,                                \
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:1100:2: note: expanded from macro 'KUNIT_BINARY_PTR_EQ_MSG_ASSERTION'
           KUNIT_BASE_EQ_MSG_ASSERTION(test,                                      \
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:989:2: note: expanded from macro 'KUNIT_BASE_EQ_MSG_ASSERTION'
           KUNIT_BASE_BINARY_ASSERTION(test,                                      \
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:964:2: note: expanded from macro 'KUNIT_BASE_BINARY_ASSERTION'
           typeof(left) __left = (left);                                          \
           ^                     ~~~~~~
   lib/kunit/kunit-test.c:334:4: note: Calling 'kunit_add_named_resource'
                           kunit_add_named_resource(test, NULL, NULL, &res1,
                           ^
   include/kunit/test.h:1451:53: note: expanded from macro 'KUNIT_EXPECT_EQ'
           KUNIT_BINARY_EQ_ASSERTION(test, KUNIT_EXPECTATION, left, right)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
   include/kunit/test.h:1090:11: note: expanded from macro 'KUNIT_BINARY_EQ_ASSERTION'
                                         left,                                    \
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:1082:9: note: expanded from macro 'KUNIT_BINARY_EQ_MSG_ASSERTION'
                                       left,                                      \
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:993:9: note: expanded from macro 'KUNIT_BASE_EQ_MSG_ASSERTION'
                                       left, ==, right,                           \
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:964:25: note: expanded from macro 'KUNIT_BASE_BINARY_ASSERTION'
           typeof(left) __left = (left);                                          \
                                  ^~~~
   include/kunit/test.h:497:7: note: 'name' is non-null
           if (!name)
                ^~~~
   include/kunit/test.h:497:2: note: Taking false branch
           if (!name)
           ^
   include/kunit/test.h:501:6: note: Assuming 'existing' is non-null
           if (existing) {
               ^~~~~~~~
   include/kunit/test.h:501:2: note: Taking true branch
           if (existing) {
           ^
   include/kunit/test.h:503:3: note: Returning without writing to 'res->data'
                   return -EEXIST;
                   ^
   lib/kunit/kunit-test.c:334:4: note: Returning from 'kunit_add_named_resource'
                           kunit_add_named_resource(test, NULL, NULL, &res1,
                           ^
   include/kunit/test.h:1451:53: note: expanded from macro 'KUNIT_EXPECT_EQ'
           KUNIT_BINARY_EQ_ASSERTION(test, KUNIT_EXPECTATION, left, right)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
   include/kunit/test.h:1090:11: note: expanded from macro 'KUNIT_BINARY_EQ_ASSERTION'
                                         left,                                    \
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:1082:9: note: expanded from macro 'KUNIT_BINARY_EQ_MSG_ASSERTION'
                                       left,                                      \
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:993:9: note: expanded from macro 'KUNIT_BASE_EQ_MSG_ASSERTION'
                                       left, ==, right,                           \
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/kunit/test.h:964:25: note: expanded from macro 'KUNIT_BASE_BINARY_ASSERTION'
           typeof(left) __left = (left);                                          \
                                  ^~~~
   lib/kunit/kunit-test.c:333:2: note: Loop condition is false.  Exiting loop
           KUNIT_EXPECT_EQ(test,
           ^
   include/kunit/test.h:1451:2: note: expanded from macro 'KUNIT_EXPECT_EQ'
           KUNIT_BINARY_EQ_ASSERTION(test, KUNIT_EXPECTATION, left, right)
           ^
   include/kunit/test.h:1088:2: note: expanded from macro 'KUNIT_BINARY_EQ_ASSERTION'
           KUNIT_BINARY_EQ_MSG_ASSERTION(test,                                    \
           ^
   include/kunit/test.h:1078:2: note: expanded from macro 'KUNIT_BINARY_EQ_MSG_ASSERTION'
           KUNIT_BASE_EQ_MSG_ASSERTION(test,                                      \
           ^
   include/kunit/test.h:989:2: note: expanded from macro 'KUNIT_BASE_EQ_MSG_ASSERTION'
           KUNIT_BASE_BINARY_ASSERTION(test,                                      \
           ^
   include/kunit/test.h:967:2: note: expanded from macro 'KUNIT_BASE_BINARY_ASSERTION'
           KUNIT_ASSERTION(test,                                                  \
           ^
   include/kunit/test.h:867:74: note: expanded from macro 'KUNIT_ASSERTION'
   #define KUNIT_ASSERTION(test, pass, assert_class, INITIALIZER, fmt, ...) do {  \
                                                                            ^
   lib/kunit/kunit-test.c:333:2: note: Loop condition is false.  Exiting loop
           KUNIT_EXPECT_EQ(test,
           ^
   include/kunit/test.h:1451:2: note: expanded from macro 'KUNIT_EXPECT_EQ'
           KUNIT_BINARY_EQ_ASSERTION(test, KUNIT_EXPECTATION, left, right)
           ^
   include/kunit/test.h:1088:2: note: expanded from macro 'KUNIT_BINARY_EQ_ASSERTION'
           KUNIT_BINARY_EQ_MSG_ASSERTION(test,                                    \
           ^
   include/kunit/test.h:1078:2: note: expanded from macro 'KUNIT_BINARY_EQ_MSG_ASSERTION'
           KUNIT_BASE_EQ_MSG_ASSERTION(test,                                      \

vim +337 lib/kunit/kunit-test.c

d4cdd146d0db90 Alan Maguire 2020-05-29  327  
725aca95859566 Alan Maguire 2020-05-29  328  static void kunit_resource_test_named(struct kunit *test)
725aca95859566 Alan Maguire 2020-05-29  329  {
725aca95859566 Alan Maguire 2020-05-29  330  	struct kunit_resource res1, res2, *found = NULL;
725aca95859566 Alan Maguire 2020-05-29  331  	struct kunit_test_resource_context ctx;
725aca95859566 Alan Maguire 2020-05-29  332  
725aca95859566 Alan Maguire 2020-05-29  333  	KUNIT_EXPECT_EQ(test,
725aca95859566 Alan Maguire 2020-05-29  334  			kunit_add_named_resource(test, NULL, NULL, &res1,
725aca95859566 Alan Maguire 2020-05-29  335  						 "resource_1", &ctx),
725aca95859566 Alan Maguire 2020-05-29  336  			0);
725aca95859566 Alan Maguire 2020-05-29 @337  	KUNIT_EXPECT_PTR_EQ(test, res1.data, (void *)&ctx);
725aca95859566 Alan Maguire 2020-05-29  338  
725aca95859566 Alan Maguire 2020-05-29  339  	KUNIT_EXPECT_EQ(test,
725aca95859566 Alan Maguire 2020-05-29  340  			kunit_add_named_resource(test, NULL, NULL, &res1,
725aca95859566 Alan Maguire 2020-05-29  341  						 "resource_1", &ctx),
725aca95859566 Alan Maguire 2020-05-29  342  			-EEXIST);
725aca95859566 Alan Maguire 2020-05-29  343  
725aca95859566 Alan Maguire 2020-05-29  344  	KUNIT_EXPECT_EQ(test,
725aca95859566 Alan Maguire 2020-05-29  345  			kunit_add_named_resource(test, NULL, NULL, &res2,
725aca95859566 Alan Maguire 2020-05-29  346  						 "resource_2", &ctx),
725aca95859566 Alan Maguire 2020-05-29  347  			0);
725aca95859566 Alan Maguire 2020-05-29  348  
725aca95859566 Alan Maguire 2020-05-29  349  	found = kunit_find_named_resource(test, "resource_1");
725aca95859566 Alan Maguire 2020-05-29  350  
725aca95859566 Alan Maguire 2020-05-29  351  	KUNIT_EXPECT_PTR_EQ(test, found, &res1);
725aca95859566 Alan Maguire 2020-05-29  352  
725aca95859566 Alan Maguire 2020-05-29  353  	if (found)
725aca95859566 Alan Maguire 2020-05-29  354  		kunit_put_resource(&res1);
725aca95859566 Alan Maguire 2020-05-29  355  
725aca95859566 Alan Maguire 2020-05-29  356  	KUNIT_EXPECT_EQ(test, kunit_destroy_named_resource(test, "resource_2"),
725aca95859566 Alan Maguire 2020-05-29  357  			0);
725aca95859566 Alan Maguire 2020-05-29  358  
725aca95859566 Alan Maguire 2020-05-29  359  	kunit_cleanup(test);
725aca95859566 Alan Maguire 2020-05-29  360  
725aca95859566 Alan Maguire 2020-05-29  361  	KUNIT_EXPECT_TRUE(test, list_empty(&test->resources));
725aca95859566 Alan Maguire 2020-05-29  362  }
725aca95859566 Alan Maguire 2020-05-29  363  

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-03-23 19:20 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-19  5:56 [PATCH] kunit: Rework kunit_resource allocation policy David Gow
2022-03-22  1:57 ` Daniel Latypov
2022-03-22  4:10   ` David Gow
2022-03-22  7:06     ` Daniel Latypov
2022-03-23  7:22       ` Brendan Higgins
2022-03-23 19:20         ` Daniel Latypov
2022-03-20  5:03 kernel test robot
2022-03-20 15:52 kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.