[PATCH] regulator: wm8400: fix reference leak on failed device registration

Guangshuo Li posted 1 patch 2 months ago
drivers/regulator/wm8400-regulator.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
[PATCH] regulator: wm8400: fix reference leak on failed device registration
Posted by Guangshuo Li 2 months ago
When platform_device_register() fails in wm8400_register_regulator(),
the embedded struct device in wm8400->regulators[reg] has already been
initialized by device_initialize(), but the failure path returns the
error without dropping the device reference for the current platform
device:

  wm8400_register_regulator()
    -> platform_device_register(&wm8400->regulators[reg])
       -> device_initialize(&wm8400->regulators[reg].dev)
       -> setup_pdev_dma_masks(&wm8400->regulators[reg])
       -> platform_device_add(&wm8400->regulators[reg])

This leads to a reference leak when platform_device_register() fails.
Fix this by calling platform_device_put() before returning the error.

The issue was identified by a static analysis tool I developed and
confirmed by manual review.

Fixes: 42fad570b6662 ("regulator: Add WM8400 regulator support")
Cc: stable@vger.kernel.org
Signed-off-by: Guangshuo Li <lgs201920130244@gmail.com>
---
 drivers/regulator/wm8400-regulator.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index fb3ca7956d00..5849bb051d2a 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -243,6 +243,7 @@ int wm8400_register_regulator(struct device *dev, int reg,
 			      struct regulator_init_data *initdata)
 {
 	struct wm8400 *wm8400 = dev_get_drvdata(dev);
+	int ret;
 
 	if (wm8400->regulators[reg].name)
 		return -EBUSY;
@@ -254,7 +255,12 @@ int wm8400_register_regulator(struct device *dev, int reg,
 	wm8400->regulators[reg].dev.parent = dev;
 	wm8400->regulators[reg].dev.platform_data = initdata;
 
-	return platform_device_register(&wm8400->regulators[reg]);
+	ret = platform_device_register(&wm8400->regulators[reg]);
+	if (ret)
+		platform_device_put(&wm8400->regulators[reg]);
+
+	return ret;
+
 }
 EXPORT_SYMBOL_GPL(wm8400_register_regulator);
 
-- 
2.43.0
Re: [PATCH] regulator: wm8400: fix reference leak on failed device registration
Posted by Mark Brown 2 months ago
On Thu, Apr 16, 2026 at 02:12:28AM +0800, Guangshuo Li wrote:
> When platform_device_register() fails in wm8400_register_regulator(),
> the embedded struct device in wm8400->regulators[reg] has already been
> initialized by device_initialize(), but the failure path returns the
> error without dropping the device reference for the current platform
> device:

> -	return platform_device_register(&wm8400->regulators[reg]);
> +	ret = platform_device_register(&wm8400->regulators[reg]);
> +	if (ret)
> +		platform_device_put(&wm8400->regulators[reg]);

Note that the device is embedded in wm8400 so we don't want to free it,
and we don't have a release() callback anyway.  The whole lifecycle is
messed up here, the subdevices should probably be dynamically allocated.
Re: [PATCH] regulator: wm8400: fix reference leak on failed device registration
Posted by Guangshuo Li 1 month, 3 weeks ago
Hi Mark,

Thanks for the review and clarification.

On Tue, 21 Apr 2026 at 01:38, Mark Brown <broonie@kernel.org> wrote:
>
> Note that the device is embedded in wm8400 so we don't want to free it,
> and we don't have a release() callback anyway.  The whole lifecycle is
> messed up here, the subdevices should probably be dynamically allocated.

You are right. The platform_device is embedded in struct wm8400 and does
not have a release callback, so calling platform_device_put() on the
platform_device_register() failure path is not appropriate here.

Please disregard this patch. I will drop it. As you said, the lifecycle
is more fundamentally wrong here and would need a different fix, such as
using dynamically allocated subdevices, rather than adding
platform_device_put() in this path.

Sorry for the noise.

Best regards,
Guangshuo Li