Skip to content

Commit 6af79f7

Browse files
Wolfram Sangwsakernel
authored andcommitted
i2c: fix memleak in i2c_new_client_device()
Yang Yingliang reported a memleak: === I got memory leak as follows when doing fault injection test: unreferenced object 0xffff888014aec078 (size 8): comm "xrun", pid 356, jiffies 4294910619 (age 16.332s) hex dump (first 8 bytes): 31 2d 30 30 31 63 00 00 1-001c.. backtrace: [<00000000eb56c0a9>] __kmalloc_track_caller+0x1a6/0x300 [<000000000b220ea3>] kvasprintf+0xad/0x140 [<00000000b83203e5>] kvasprintf_const+0x62/0x190 [<000000002a5eab37>] kobject_set_name_vargs+0x56/0x140 [<00000000300ac279>] dev_set_name+0xb0/0xe0 [<00000000b66ebd6f>] i2c_new_client_device+0x7e4/0x9a0 If device_register() returns error in i2c_new_client_device(), the name allocated by i2c_dev_set_name() need be freed. As comment of device_register() says, it should use put_device() to give up the reference in the error path. === I think this solution is less intrusive and more robust than he originally proposed solutions, though. Reported-by: Yang Yingliang <[email protected]> Closes: http://patchwork.ozlabs.org/project/linux-i2c/patch/[email protected]/ Signed-off-by: Wolfram Sang <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 8c906cc commit 6af79f7

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

drivers/i2c/i2c-core-base.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -931,8 +931,9 @@ int i2c_dev_irq_from_resources(const struct resource *resources,
931931
struct i2c_client *
932932
i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
933933
{
934-
struct i2c_client *client;
935-
int status;
934+
struct i2c_client *client;
935+
bool need_put = false;
936+
int status;
936937

937938
client = kzalloc(sizeof *client, GFP_KERNEL);
938939
if (!client)
@@ -970,7 +971,6 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
970971
client->dev.fwnode = info->fwnode;
971972

972973
device_enable_async_suspend(&client->dev);
973-
i2c_dev_set_name(adap, client, info);
974974

975975
if (info->swnode) {
976976
status = device_add_software_node(&client->dev, info->swnode);
@@ -982,6 +982,7 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
982982
}
983983
}
984984

985+
i2c_dev_set_name(adap, client, info);
985986
status = device_register(&client->dev);
986987
if (status)
987988
goto out_remove_swnode;
@@ -993,14 +994,18 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
993994

994995
out_remove_swnode:
995996
device_remove_software_node(&client->dev);
997+
need_put = true;
996998
out_err_put_of_node:
997999
of_node_put(info->of_node);
9981000
out_err:
9991001
dev_err(&adap->dev,
10001002
"Failed to register i2c client %s at 0x%02x (%d)\n",
10011003
client->name, client->addr, status);
10021004
out_err_silent:
1003-
kfree(client);
1005+
if (need_put)
1006+
put_device(&client->dev);
1007+
else
1008+
kfree(client);
10041009
return ERR_PTR(status);
10051010
}
10061011
EXPORT_SYMBOL_GPL(i2c_new_client_device);

0 commit comments

Comments
 (0)