linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/5] kunit: string-stream: Simplify resource use
@ 2022-07-22 17:15 Daniel Latypov
  2022-07-22 17:15 ` [PATCH v2 2/5] kunit: drop test pointer in string_stream_fragment Daniel Latypov
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Daniel Latypov @ 2022-07-22 17:15 UTC (permalink / raw)
  To: brendanhiggins, davidgow
  Cc: linux-kernel, kunit-dev, linux-kselftest, skhan, Daniel Latypov

From: David Gow <davidgow@google.com>

Currently, KUnit's string streams are themselves "KUnit resources".
This is redundant since the stream itself is already allocated with
kunit_kzalloc() and will thus be freed automatically at the end of the
test.

string-stream is only used internally within KUnit, and isn't using the
extra features that resources provide like reference counting, being
able to locate them dynamically as "test-local variables", etc.

Indeed, the resource's refcount is never incremented when the
pointer is returned. The fact that it's always manually destroyed is
more evidence that the reference counting is unused.

Signed-off-by: David Gow <davidgow@google.com>
Signed-off-by: Daniel Latypov <dlatypov@google.com>
---
v1 -> v2: no changes
---
 lib/kunit/string-stream.c | 90 +++++++--------------------------------
 lib/kunit/string-stream.h |  2 +-
 lib/kunit/test.c          |  2 +-
 3 files changed, 18 insertions(+), 76 deletions(-)

diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
index 141789ca8949..a2496abef152 100644
--- a/lib/kunit/string-stream.c
+++ b/lib/kunit/string-stream.c
@@ -12,64 +12,31 @@
 
 #include "string-stream.h"
 
-struct string_stream_fragment_alloc_context {
-	struct kunit *test;
-	int len;
-	gfp_t gfp;
-};
 
-static int string_stream_fragment_init(struct kunit_resource *res,
-				       void *context)
+static struct string_stream_fragment *alloc_string_stream_fragment(
+		struct kunit *test, int len, gfp_t gfp)
 {
-	struct string_stream_fragment_alloc_context *ctx = context;
 	struct string_stream_fragment *frag;
 
-	frag = kunit_kzalloc(ctx->test, sizeof(*frag), ctx->gfp);
+	frag = kunit_kzalloc(test, sizeof(*frag), gfp);
 	if (!frag)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	frag->test = ctx->test;
-	frag->fragment = kunit_kmalloc(ctx->test, ctx->len, ctx->gfp);
+	frag->test = test;
+	frag->fragment = kunit_kmalloc(test, len, gfp);
 	if (!frag->fragment)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	res->data = frag;
-
-	return 0;
+	return frag;
 }
 
-static void string_stream_fragment_free(struct kunit_resource *res)
+static void string_stream_fragment_destroy(struct string_stream_fragment *frag)
 {
-	struct string_stream_fragment *frag = res->data;
-
 	list_del(&frag->node);
 	kunit_kfree(frag->test, frag->fragment);
 	kunit_kfree(frag->test, frag);
 }
 
-static struct string_stream_fragment *alloc_string_stream_fragment(
-		struct kunit *test, int len, gfp_t gfp)
-{
-	struct string_stream_fragment_alloc_context context = {
-		.test = test,
-		.len = len,
-		.gfp = gfp
-	};
-
-	return kunit_alloc_resource(test,
-				    string_stream_fragment_init,
-				    string_stream_fragment_free,
-				    gfp,
-				    &context);
-}
-
-static int string_stream_fragment_destroy(struct string_stream_fragment *frag)
-{
-	return kunit_destroy_resource(frag->test,
-				      kunit_resource_instance_match,
-				      frag);
-}
-
 int string_stream_vadd(struct string_stream *stream,
 		       const char *fmt,
 		       va_list args)
@@ -169,48 +136,23 @@ struct string_stream_alloc_context {
 	gfp_t gfp;
 };
 
-static int string_stream_init(struct kunit_resource *res, void *context)
+struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
 {
 	struct string_stream *stream;
-	struct string_stream_alloc_context *ctx = context;
 
-	stream = kunit_kzalloc(ctx->test, sizeof(*stream), ctx->gfp);
+	stream = kunit_kzalloc(test, sizeof(*stream), gfp);
 	if (!stream)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
-	res->data = stream;
-	stream->gfp = ctx->gfp;
-	stream->test = ctx->test;
+	stream->gfp = gfp;
+	stream->test = test;
 	INIT_LIST_HEAD(&stream->fragments);
 	spin_lock_init(&stream->lock);
 
-	return 0;
+	return stream;
 }
 
-static void string_stream_free(struct kunit_resource *res)
+void string_stream_destroy(struct string_stream *stream)
 {
-	struct string_stream *stream = res->data;
-
 	string_stream_clear(stream);
 }
-
-struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
-{
-	struct string_stream_alloc_context context = {
-		.test = test,
-		.gfp = gfp
-	};
-
-	return kunit_alloc_resource(test,
-				    string_stream_init,
-				    string_stream_free,
-				    gfp,
-				    &context);
-}
-
-int string_stream_destroy(struct string_stream *stream)
-{
-	return kunit_destroy_resource(stream->test,
-				      kunit_resource_instance_match,
-				      stream);
-}
diff --git a/lib/kunit/string-stream.h b/lib/kunit/string-stream.h
index 43f9508a55b4..494dee0f24bd 100644
--- a/lib/kunit/string-stream.h
+++ b/lib/kunit/string-stream.h
@@ -46,6 +46,6 @@ int string_stream_append(struct string_stream *stream,
 
 bool string_stream_is_empty(struct string_stream *stream);
 
-int string_stream_destroy(struct string_stream *stream);
+void string_stream_destroy(struct string_stream *stream);
 
 #endif /* _KUNIT_STRING_STREAM_H */
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index b73d5bb5c473..0fb2771ca03e 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -267,7 +267,7 @@ static void kunit_fail(struct kunit *test, const struct kunit_loc *loc,
 
 	kunit_print_string_stream(test, stream);
 
-	WARN_ON(string_stream_destroy(stream));
+	string_stream_destroy(stream);
 }
 
 static void __noreturn kunit_abort(struct kunit *test)

base-commit: 94681e289bf5d10c9db9db143d1a22d8717205c5
-- 
2.37.1.359.gd136c6c3e2-goog


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

* [PATCH v2 2/5] kunit: drop test pointer in string_stream_fragment
  2022-07-22 17:15 [PATCH v2 1/5] kunit: string-stream: Simplify resource use Daniel Latypov
@ 2022-07-22 17:15 ` Daniel Latypov
  2022-10-05 20:30   ` Brendan Higgins
  2022-07-22 17:15 ` [PATCH v2 3/5] kunit: make kunit_kfree() only work on pointers from kunit_malloc() and friends Daniel Latypov
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Daniel Latypov @ 2022-07-22 17:15 UTC (permalink / raw)
  To: brendanhiggins, davidgow
  Cc: linux-kernel, kunit-dev, linux-kselftest, skhan, Daniel Latypov

We already store the `struct kunit *test` in the string_stream object
itself, so we need don't need to store a copy of this pointer in every
fragment in the stream.

Drop it, getting string_stream_fragment down the bare minimum: a
list_head and the `char *` with the actual fragment.

Signed-off-by: Daniel Latypov <dlatypov@google.com>
Reviewed-by: David Gow <davidgow@google.com>
---
v1 -> v2: no changes
---
 lib/kunit/string-stream.c | 10 +++++-----
 lib/kunit/string-stream.h |  1 -
 2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/lib/kunit/string-stream.c b/lib/kunit/string-stream.c
index a2496abef152..f5ae79c37400 100644
--- a/lib/kunit/string-stream.c
+++ b/lib/kunit/string-stream.c
@@ -22,7 +22,6 @@ static struct string_stream_fragment *alloc_string_stream_fragment(
 	if (!frag)
 		return ERR_PTR(-ENOMEM);
 
-	frag->test = test;
 	frag->fragment = kunit_kmalloc(test, len, gfp);
 	if (!frag->fragment)
 		return ERR_PTR(-ENOMEM);
@@ -30,11 +29,12 @@ static struct string_stream_fragment *alloc_string_stream_fragment(
 	return frag;
 }
 
-static void string_stream_fragment_destroy(struct string_stream_fragment *frag)
+static void string_stream_fragment_destroy(struct kunit *test,
+					   struct string_stream_fragment *frag)
 {
 	list_del(&frag->node);
-	kunit_kfree(frag->test, frag->fragment);
-	kunit_kfree(frag->test, frag);
+	kunit_kfree(test, frag->fragment);
+	kunit_kfree(test, frag);
 }
 
 int string_stream_vadd(struct string_stream *stream,
@@ -89,7 +89,7 @@ static void string_stream_clear(struct string_stream *stream)
 				 frag_container_safe,
 				 &stream->fragments,
 				 node) {
-		string_stream_fragment_destroy(frag_container);
+		string_stream_fragment_destroy(stream->test, frag_container);
 	}
 	stream->length = 0;
 	spin_unlock(&stream->lock);
diff --git a/lib/kunit/string-stream.h b/lib/kunit/string-stream.h
index 494dee0f24bd..b669f9a75a94 100644
--- a/lib/kunit/string-stream.h
+++ b/lib/kunit/string-stream.h
@@ -14,7 +14,6 @@
 #include <linux/stdarg.h>
 
 struct string_stream_fragment {
-	struct kunit *test;
 	struct list_head node;
 	char *fragment;
 };
-- 
2.37.1.359.gd136c6c3e2-goog


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

* [PATCH v2 3/5] kunit: make kunit_kfree() only work on pointers from kunit_malloc() and friends
  2022-07-22 17:15 [PATCH v2 1/5] kunit: string-stream: Simplify resource use Daniel Latypov
  2022-07-22 17:15 ` [PATCH v2 2/5] kunit: drop test pointer in string_stream_fragment Daniel Latypov
@ 2022-07-22 17:15 ` Daniel Latypov
  2022-10-05 20:36   ` Brendan Higgins
  2022-07-22 17:15 ` [PATCH v2 4/5] kunit: make kunit_kfree() not segfault on invalid inputs Daniel Latypov
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Daniel Latypov @ 2022-07-22 17:15 UTC (permalink / raw)
  To: brendanhiggins, davidgow
  Cc: linux-kernel, kunit-dev, linux-kselftest, skhan, Daniel Latypov

kunit_kfree() exists to clean up allocations from kunit_kmalloc() and
friends early instead of waiting for this to happen automatically at the
end of the test.

But it can be used on *anything* registered with the kunit resource API.

E.g. the last 2 statements are equivalent:
  struct kunit_resource *res = something();
  kfree(res->data);
  kunit_put_resource(res);

The problem is that there could be multiple resources that point to the
same `data`.

E.g. you can have a named resource acting as a pseudo-global variable in
a test. If you point it to data allocated with kunit_kmalloc(), then
calling `kunit_kfree(ptr)` has the chance to delete either the named
resource or to kfree `ptr`.
Which one it does depends on the order the resources are registered as
kunit_kfree() will delete resources in LIFO order.

So this patch restricts kunit_kfree() to only working on resources
created by kunit_kmalloc(). Calling it is therefore guaranteed to free
the memory, not do anything else.

Note: kunit_resource_instance_match() wasn't used outside of KUnit, so
it should be safe to remove from the public interface. It's also
generally dangerous, as shown above, and shouldn't be used.

Signed-off-by: Daniel Latypov <dlatypov@google.com>
Reviewed-by: David Gow <davidgow@google.com>
---
v1 -> v2: no changes
---
 include/kunit/resource.h | 16 ----------------
 lib/kunit/kunit-test.c   |  7 +++++++
 lib/kunit/test.c         | 10 ++++++++--
 3 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/include/kunit/resource.h b/include/kunit/resource.h
index 09c2b34d1c61..cf6fb8f2ac1b 100644
--- a/include/kunit/resource.h
+++ b/include/kunit/resource.h
@@ -300,22 +300,6 @@ typedef bool (*kunit_resource_match_t)(struct kunit *test,
 				       struct kunit_resource *res,
 				       void *match_data);
 
-/**
- * kunit_resource_instance_match() - Match a resource with the same instance.
- * @test: Test case to which the resource belongs.
- * @res: The resource.
- * @match_data: The resource pointer to match against.
- *
- * An instance of kunit_resource_match_t that matches a resource whose
- * allocation matches @match_data.
- */
-static inline bool kunit_resource_instance_match(struct kunit *test,
-						 struct kunit_resource *res,
-						 void *match_data)
-{
-	return res->data == match_data;
-}
-
 /**
  * kunit_resource_name_match() - Match a resource with the same name.
  * @test: Test case to which the resource belongs.
diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
index 13d0bd8b07a9..4df0335d0d06 100644
--- a/lib/kunit/kunit-test.c
+++ b/lib/kunit/kunit-test.c
@@ -161,6 +161,13 @@ static void kunit_resource_test_alloc_resource(struct kunit *test)
 	kunit_put_resource(res);
 }
 
+static inline bool kunit_resource_instance_match(struct kunit *test,
+						 struct kunit_resource *res,
+						 void *match_data)
+{
+	return res->data == match_data;
+}
+
 /*
  * Note: tests below use kunit_alloc_and_get_resource(), so as a consequence
  * they have a reference to the associated resource that they must release
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 0fb2771ca03e..82019a78462e 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -689,12 +689,18 @@ void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp)
 }
 EXPORT_SYMBOL_GPL(kunit_kmalloc_array);
 
+static inline bool kunit_kfree_match(struct kunit *test,
+				     struct kunit_resource *res, void *match_data)
+{
+	/* Only match resources allocated with kunit_kmalloc() and friends. */
+	return res->free == kunit_kmalloc_array_free && res->data == match_data;
+}
+
 void kunit_kfree(struct kunit *test, const void *ptr)
 {
 	struct kunit_resource *res;
 
-	res = kunit_find_resource(test, kunit_resource_instance_match,
-				  (void *)ptr);
+	res = kunit_find_resource(test, kunit_kfree_match, (void *)ptr);
 
 	/*
 	 * Removing the resource from the list of resources drops the
-- 
2.37.1.359.gd136c6c3e2-goog


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

* [PATCH v2 4/5] kunit: make kunit_kfree() not segfault on invalid inputs
  2022-07-22 17:15 [PATCH v2 1/5] kunit: string-stream: Simplify resource use Daniel Latypov
  2022-07-22 17:15 ` [PATCH v2 2/5] kunit: drop test pointer in string_stream_fragment Daniel Latypov
  2022-07-22 17:15 ` [PATCH v2 3/5] kunit: make kunit_kfree() only work on pointers from kunit_malloc() and friends Daniel Latypov
@ 2022-07-22 17:15 ` Daniel Latypov
  2022-10-05 20:39   ` Brendan Higgins
  2022-07-22 17:15 ` [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree() Daniel Latypov
  2022-10-05 20:28 ` [PATCH v2 1/5] kunit: string-stream: Simplify resource use Brendan Higgins
  4 siblings, 1 reply; 11+ messages in thread
From: Daniel Latypov @ 2022-07-22 17:15 UTC (permalink / raw)
  To: brendanhiggins, davidgow
  Cc: linux-kernel, kunit-dev, linux-kselftest, skhan, Daniel Latypov

kunit_kfree() can only work on data ("resources") allocated by KUnit.

Currently for code like this,
> void *ptr = kmalloc(4, GFP_KERNEL);
> kunit_kfree(test, ptr);
kunit_kfree() will segfault.

It'll try and look up the kunit_resource associated with `ptr` and get a
NULL back, but it won't check for this. This means we also segfault if
you double-free.

Change kunit_kfree() so it'll notice these invalid pointers and respond
by failing the test.

Implementation: kunit_destroy_resource() does what kunit_kfree() does,
but is more generic and returns -ENOENT when it can't find the resource.
Sadly, unlike just letting it crash, this means we don't get a stack
trace. But kunit_kfree() is so infrequently used it shouldn't be hard to
track down the bad callsite anyways.

After this change, the above code gives:
> # example_simple_test: EXPECTATION FAILED at lib/kunit/test.c:702
> kunit_kfree: 00000000626ec200 already freed or not allocated by kunit

Signed-off-by: Daniel Latypov <dlatypov@google.com>
Reviewed-by: David Gow <davidgow@google.com>
---
v1 -> v2: fix typo in commit desc.
---
 lib/kunit/test.c | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 82019a78462e..c7ca87484968 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -698,18 +698,8 @@ static inline bool kunit_kfree_match(struct kunit *test,
 
 void kunit_kfree(struct kunit *test, const void *ptr)
 {
-	struct kunit_resource *res;
-
-	res = kunit_find_resource(test, kunit_kfree_match, (void *)ptr);
-
-	/*
-	 * Removing the resource from the list of resources drops the
-	 * reference count to 1; the final put will trigger the free.
-	 */
-	kunit_remove_resource(test, res);
-
-	kunit_put_resource(res);
-
+	if (kunit_destroy_resource(test, kunit_kfree_match, (void *)ptr))
+		KUNIT_FAIL(test, "kunit_kfree: %px already freed or not allocated by kunit", ptr);
 }
 EXPORT_SYMBOL_GPL(kunit_kfree);
 
-- 
2.37.1.359.gd136c6c3e2-goog


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

* [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree()
  2022-07-22 17:15 [PATCH v2 1/5] kunit: string-stream: Simplify resource use Daniel Latypov
                   ` (2 preceding siblings ...)
  2022-07-22 17:15 ` [PATCH v2 4/5] kunit: make kunit_kfree() not segfault on invalid inputs Daniel Latypov
@ 2022-07-22 17:15 ` Daniel Latypov
  2022-07-23  6:33   ` David Gow
  2022-10-05 20:40   ` Brendan Higgins
  2022-10-05 20:28 ` [PATCH v2 1/5] kunit: string-stream: Simplify resource use Brendan Higgins
  4 siblings, 2 replies; 11+ messages in thread
From: Daniel Latypov @ 2022-07-22 17:15 UTC (permalink / raw)
  To: brendanhiggins, davidgow
  Cc: linux-kernel, kunit-dev, linux-kselftest, skhan, Daniel Latypov

The real kfree() function will silently return when given a NULL.
So a user might reasonably think they can write the following code:
  char *buffer = NULL;
  if (param->use_buffer) buffer = kunit_kzalloc(test, 10, GFP_KERNEL);
  ...
  kunit_kfree(test, buffer);

As-is, kunit_kfree() will mark the test as FAILED when buffer is NULL.
(And in earlier times, it would segfault).

Let's match the semantics of kfree().

Suggested-by: David Gow <davidgow@google.com>
Signed-off-by: Daniel Latypov <dlatypov@google.com>
---
v1 -> v2: add this patch to the series.
---
 lib/kunit/test.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index c7ca87484968..879c8db36cb5 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -698,6 +698,9 @@ static inline bool kunit_kfree_match(struct kunit *test,
 
 void kunit_kfree(struct kunit *test, const void *ptr)
 {
+	if (!ptr)
+		return;
+
 	if (kunit_destroy_resource(test, kunit_kfree_match, (void *)ptr))
 		KUNIT_FAIL(test, "kunit_kfree: %px already freed or not allocated by kunit", ptr);
 }
-- 
2.37.1.359.gd136c6c3e2-goog


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

* Re: [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree()
  2022-07-22 17:15 ` [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree() Daniel Latypov
@ 2022-07-23  6:33   ` David Gow
  2022-10-05 20:40   ` Brendan Higgins
  1 sibling, 0 replies; 11+ messages in thread
From: David Gow @ 2022-07-23  6:33 UTC (permalink / raw)
  To: Daniel Latypov
  Cc: Brendan Higgins, Linux Kernel Mailing List, KUnit Development,
	open list:KERNEL SELFTEST FRAMEWORK, Shuah Khan

On Sat, Jul 23, 2022 at 1:15 AM Daniel Latypov <dlatypov@google.com> wrote:
>
> The real kfree() function will silently return when given a NULL.
> So a user might reasonably think they can write the following code:
>   char *buffer = NULL;
>   if (param->use_buffer) buffer = kunit_kzalloc(test, 10, GFP_KERNEL);
>   ...
>   kunit_kfree(test, buffer);
>
> As-is, kunit_kfree() will mark the test as FAILED when buffer is NULL.
> (And in earlier times, it would segfault).
>
> Let's match the semantics of kfree().
>
> Suggested-by: David Gow <davidgow@google.com>
> Signed-off-by: Daniel Latypov <dlatypov@google.com>
> ---
> v1 -> v2: add this patch to the series.
> ---

Thanks! This looks good to me, and worked with a basic test.

Reviewed-by: David Gow <davidgow@google.com>

Cheers,
-- David

>  lib/kunit/test.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/lib/kunit/test.c b/lib/kunit/test.c
> index c7ca87484968..879c8db36cb5 100644
> --- a/lib/kunit/test.c
> +++ b/lib/kunit/test.c
> @@ -698,6 +698,9 @@ static inline bool kunit_kfree_match(struct kunit *test,
>
>  void kunit_kfree(struct kunit *test, const void *ptr)
>  {
> +       if (!ptr)
> +               return;
> +
>         if (kunit_destroy_resource(test, kunit_kfree_match, (void *)ptr))
>                 KUNIT_FAIL(test, "kunit_kfree: %px already freed or not allocated by kunit", ptr);
>  }
> --
> 2.37.1.359.gd136c6c3e2-goog
>

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

* Re: [PATCH v2 1/5] kunit: string-stream: Simplify resource use
  2022-07-22 17:15 [PATCH v2 1/5] kunit: string-stream: Simplify resource use Daniel Latypov
                   ` (3 preceding siblings ...)
  2022-07-22 17:15 ` [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree() Daniel Latypov
@ 2022-10-05 20:28 ` Brendan Higgins
  4 siblings, 0 replies; 11+ messages in thread
From: Brendan Higgins @ 2022-10-05 20:28 UTC (permalink / raw)
  To: Daniel Latypov; +Cc: davidgow, linux-kernel, kunit-dev, linux-kselftest, skhan

On Fri, Jul 22, 2022 at 1:15 PM 'Daniel Latypov' via KUnit Development
<kunit-dev@googlegroups.com> wrote:
>
> From: David Gow <davidgow@google.com>
>
> Currently, KUnit's string streams are themselves "KUnit resources".
> This is redundant since the stream itself is already allocated with
> kunit_kzalloc() and will thus be freed automatically at the end of the
> test.
>
> string-stream is only used internally within KUnit, and isn't using the
> extra features that resources provide like reference counting, being
> able to locate them dynamically as "test-local variables", etc.
>
> Indeed, the resource's refcount is never incremented when the
> pointer is returned. The fact that it's always manually destroyed is
> more evidence that the reference counting is unused.
>
> Signed-off-by: David Gow <davidgow@google.com>
> Signed-off-by: Daniel Latypov <dlatypov@google.com>

Reviewed-by: Brendan Higgins <brendanhiggins@google.com>

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

* Re: [PATCH v2 2/5] kunit: drop test pointer in string_stream_fragment
  2022-07-22 17:15 ` [PATCH v2 2/5] kunit: drop test pointer in string_stream_fragment Daniel Latypov
@ 2022-10-05 20:30   ` Brendan Higgins
  0 siblings, 0 replies; 11+ messages in thread
From: Brendan Higgins @ 2022-10-05 20:30 UTC (permalink / raw)
  To: Daniel Latypov; +Cc: davidgow, linux-kernel, kunit-dev, linux-kselftest, skhan

On Fri, Jul 22, 2022 at 1:15 PM Daniel Latypov <dlatypov@google.com> wrote:
>
> We already store the `struct kunit *test` in the string_stream object
> itself, so we need don't need to store a copy of this pointer in every
> fragment in the stream.
>
> Drop it, getting string_stream_fragment down the bare minimum: a
> list_head and the `char *` with the actual fragment.
>
> Signed-off-by: Daniel Latypov <dlatypov@google.com>
> Reviewed-by: David Gow <davidgow@google.com>

Reviewed-by: Brendan Higgins <brendanhiggins@google.com>

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

* Re: [PATCH v2 3/5] kunit: make kunit_kfree() only work on pointers from kunit_malloc() and friends
  2022-07-22 17:15 ` [PATCH v2 3/5] kunit: make kunit_kfree() only work on pointers from kunit_malloc() and friends Daniel Latypov
@ 2022-10-05 20:36   ` Brendan Higgins
  0 siblings, 0 replies; 11+ messages in thread
From: Brendan Higgins @ 2022-10-05 20:36 UTC (permalink / raw)
  To: Daniel Latypov; +Cc: davidgow, linux-kernel, kunit-dev, linux-kselftest, skhan

On Fri, Jul 22, 2022 at 1:15 PM Daniel Latypov <dlatypov@google.com> wrote:
>
> kunit_kfree() exists to clean up allocations from kunit_kmalloc() and
> friends early instead of waiting for this to happen automatically at the
> end of the test.
>
> But it can be used on *anything* registered with the kunit resource API.
>
> E.g. the last 2 statements are equivalent:
>   struct kunit_resource *res = something();
>   kfree(res->data);
>   kunit_put_resource(res);
>
> The problem is that there could be multiple resources that point to the
> same `data`.
>
> E.g. you can have a named resource acting as a pseudo-global variable in
> a test. If you point it to data allocated with kunit_kmalloc(), then
> calling `kunit_kfree(ptr)` has the chance to delete either the named
> resource or to kfree `ptr`.
> Which one it does depends on the order the resources are registered as
> kunit_kfree() will delete resources in LIFO order.
>
> So this patch restricts kunit_kfree() to only working on resources
> created by kunit_kmalloc(). Calling it is therefore guaranteed to free
> the memory, not do anything else.
>
> Note: kunit_resource_instance_match() wasn't used outside of KUnit, so
> it should be safe to remove from the public interface. It's also
> generally dangerous, as shown above, and shouldn't be used.
>
> Signed-off-by: Daniel Latypov <dlatypov@google.com>
> Reviewed-by: David Gow <davidgow@google.com>

Reviewed-by: Brendan Higgins <brendanhiggins@google.com>

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

* Re: [PATCH v2 4/5] kunit: make kunit_kfree() not segfault on invalid inputs
  2022-07-22 17:15 ` [PATCH v2 4/5] kunit: make kunit_kfree() not segfault on invalid inputs Daniel Latypov
@ 2022-10-05 20:39   ` Brendan Higgins
  0 siblings, 0 replies; 11+ messages in thread
From: Brendan Higgins @ 2022-10-05 20:39 UTC (permalink / raw)
  To: Daniel Latypov; +Cc: davidgow, linux-kernel, kunit-dev, linux-kselftest, skhan

On Fri, Jul 22, 2022 at 1:15 PM Daniel Latypov <dlatypov@google.com> wrote:
>
> kunit_kfree() can only work on data ("resources") allocated by KUnit.
>
> Currently for code like this,
> > void *ptr = kmalloc(4, GFP_KERNEL);
> > kunit_kfree(test, ptr);
> kunit_kfree() will segfault.
>
> It'll try and look up the kunit_resource associated with `ptr` and get a
> NULL back, but it won't check for this. This means we also segfault if
> you double-free.
>
> Change kunit_kfree() so it'll notice these invalid pointers and respond
> by failing the test.
>
> Implementation: kunit_destroy_resource() does what kunit_kfree() does,
> but is more generic and returns -ENOENT when it can't find the resource.
> Sadly, unlike just letting it crash, this means we don't get a stack
> trace. But kunit_kfree() is so infrequently used it shouldn't be hard to
> track down the bad callsite anyways.
>
> After this change, the above code gives:
> > # example_simple_test: EXPECTATION FAILED at lib/kunit/test.c:702
> > kunit_kfree: 00000000626ec200 already freed or not allocated by kunit
>
> Signed-off-by: Daniel Latypov <dlatypov@google.com>
> Reviewed-by: David Gow <davidgow@google.com>

Reviewed-by: Brendan Higgins <brendanhiggins@google.com>

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

* Re: [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree()
  2022-07-22 17:15 ` [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree() Daniel Latypov
  2022-07-23  6:33   ` David Gow
@ 2022-10-05 20:40   ` Brendan Higgins
  1 sibling, 0 replies; 11+ messages in thread
From: Brendan Higgins @ 2022-10-05 20:40 UTC (permalink / raw)
  To: Daniel Latypov; +Cc: davidgow, linux-kernel, kunit-dev, linux-kselftest, skhan

On Fri, Jul 22, 2022 at 1:15 PM Daniel Latypov <dlatypov@google.com> wrote:
>
> The real kfree() function will silently return when given a NULL.
> So a user might reasonably think they can write the following code:
>   char *buffer = NULL;
>   if (param->use_buffer) buffer = kunit_kzalloc(test, 10, GFP_KERNEL);
>   ...
>   kunit_kfree(test, buffer);
>
> As-is, kunit_kfree() will mark the test as FAILED when buffer is NULL.
> (And in earlier times, it would segfault).
>
> Let's match the semantics of kfree().
>
> Suggested-by: David Gow <davidgow@google.com>
> Signed-off-by: Daniel Latypov <dlatypov@google.com>

Reviewed-by: Brendan Higgins <brendanhiggins@google.com>

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

end of thread, other threads:[~2022-10-05 20:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-22 17:15 [PATCH v2 1/5] kunit: string-stream: Simplify resource use Daniel Latypov
2022-07-22 17:15 ` [PATCH v2 2/5] kunit: drop test pointer in string_stream_fragment Daniel Latypov
2022-10-05 20:30   ` Brendan Higgins
2022-07-22 17:15 ` [PATCH v2 3/5] kunit: make kunit_kfree() only work on pointers from kunit_malloc() and friends Daniel Latypov
2022-10-05 20:36   ` Brendan Higgins
2022-07-22 17:15 ` [PATCH v2 4/5] kunit: make kunit_kfree() not segfault on invalid inputs Daniel Latypov
2022-10-05 20:39   ` Brendan Higgins
2022-07-22 17:15 ` [PATCH v2 5/5] kunit: make kunit_kfree(NULL) a no-op to match kfree() Daniel Latypov
2022-07-23  6:33   ` David Gow
2022-10-05 20:40   ` Brendan Higgins
2022-10-05 20:28 ` [PATCH v2 1/5] kunit: string-stream: Simplify resource use Brendan Higgins

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).