Skip to contentSkip to conversation

Fix memory leak in qcserial driver

PATCH In review Steven Hardy 4 participants 16 messages Mar 28, 2011 – Apr 4, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Fix memory leak in qcserial driver

Hi,

I've been experimenting with kmemleak and noticed a recurring leak warning whenever I load & unload the qcserial driver.

Inspection of the code seems to indicate the leak is the serial->private data allocated in the qcprobe() function, which is never freed (apart from in some of the qcprobe error paths) as far as I can tell.

The patch below fixes the following problems:
1 - Always free the serial->private data allocated in qcprobe, added a new function qc_release which frees the memory rather than relying on the usb_wwan_release function which does not. Without this cleanup, we leak the memory allocated in qcprobe when the kfree(serial) happens in usb-serial.c::destroy_serial()

2 - Ensure that the serial->private data is freed in the event of the probe failing and returning -ENODEV. This error-path leak is less likely but still possible, it was discussed previously but not actually fixed AFAICS:
http://kerneltrap.org/mailarchive/linux-kernel/2010/6/14/4582980/thread,
http://lkml.org/lkml/2010/6/20/234

3 - Don't assign serial->private when doing the kzalloc or serial->private ends up pointing to freed memory in the event we return -ENODEV, instead call usb_set_serial_data(serial, data) at the end of the function, and only have one return.

Please keep me on CC for any responses or review comments, since I'm not currently subscribed to LKML

drivers/usb/serial/qcserial.c +23 -7
index 8858201..e66530a 100644
@@ -111,7 +111,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	ifnum = intf->desc.bInterfaceNumber;
 	dbg("This Interface = %d", ifnum);
 
-	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
+	data = kzalloc(sizeof(struct usb_wwan_intf_private),
 					 GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -134,8 +134,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 		    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
 			dbg("QDL port found");
 
-			if (serial->interface->num_altsetting == 1)
-				return 0;
+			if (serial->interface->num_altsetting == 1) {
+				retval = 0;	/* Success */
+				break;
+			}
 
 			retval = usb_set_interface(serial->dev, ifnum, 1);
 			if (retval < 0) {
@@ -145,7 +147,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		}
 		break;
 
@@ -166,6 +167,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
+				kfree(data);
 			}
 		} else if (ifnum == 2) {
 			dbg("Modem port found");
@@ -177,7 +179,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		} else if (ifnum==3) {
 			/*
 			 * NMEA (serial line 9600 8N1)
@@ -191,6 +192,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
+				kfree(data);
 			}
 		}
 		break;
@@ -198,13 +200,27 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	default:
 		dev_err(&serial->dev->dev,
 			"unknown number of interfaces: %d\n", nintf);
+		retval = -ENODEV;
 		kfree(data);
-		return -ENODEV;
 	}
 
+	/* Set serial->private may be null if -ENODEV */
+	usb_set_serial_data(serial, data);
 	return retval;
 }
 
+static void qc_release(struct usb_serial *serial)
+{
+	struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
+
+	dbg("%s", __func__);
+
+	/* Call usb_wwan release & free the private data allocated in qcprobe */
+	usb_wwan_release(serial);
+	usb_set_serial_data(serial, NULL);
+	kfree(priv);
+}
+
 static struct usb_serial_driver qcdevice = {
 	.driver = {
 		.owner     = THIS_MODULE,
@@ -222,7 +238,7 @@ static struct usb_serial_driver qcdevice = {
 	.chars_in_buffer     = usb_wwan_chars_in_buffer,
 	.attach		     = usb_wwan_startup,
 	.disconnect	     = usb_wwan_disconnect,
-	.release	     = usb_wwan_release,
+	.release	     = qc_release,
 #ifdef CONFIG_PM
 	.suspend	     = usb_wwan_suspend,
 	.resume		     = usb_wwan_resume,
#1 lore raw
Quoted 8 lines · Steven Hardy

Hi,

I've been experimenting with kmemleak and noticed a recurring leak warning whenever I load & unload the qcserial driver.

Inspection of the code seems to indicate the leak is the serial->private data allocated in the qcprobe() function, which is never freed (apart from in some of the qcprobe error paths) as far as I can tell.

The patch below fixes the following problems:

<snip>

Can you fix your email client to properly wrap your lines?

Also, as you do 3 different things here, can you break this into 3 patches and resend them?

thanks,

greg k-h

#2 lore raw

PATCH 1/3 Resend : Fix memory leak in qcserial driver

Quoted 5 lines · Greg KH
Quoted 4 lines · Steven Hardy

Hi,

I've been experimenting with kmemleak and noticed a recurring leak warning whenever I load & unload the qcserial driver.

Quoted 8 lines
Quoted 4 lines

Inspection of the code seems to indicate the leak is the serial->private data allocated in the qcprobe() function, which is never freed (apart from in some of the qcprobe error paths) as far as I can tell.

The patch below fixes the following problems:

<snip>

Can you fix your email client to properly wrap your lines?

Apologies, was trying to avoid mangling the patch & ended up mangling the preamble instead, back to mutt now which will hopefully do the right thing! :)

Quoted 2 lines

Also, as you do 3 different things here, can you break this into 3 patches and resend them?

Done, please find patch 1 of 3 below:

The patch below fixes the following problem:
1 - Always free the serial->private data allocated in qcprobe, added a new function qc_release which frees the memory rather than relying on the usb_wwan_release function which does not. Without this cleanup, we leak the memory allocated in qcprobe when the kfree(serial) happens in usb-serial.c::destroy_serial()

Please keep me on CC for any responses or review comments, since I'm not currently subscribed to LKML

drivers/usb/serial/qcserial.c +13 -1
index 8858201..6e3b933 100644
@@ -205,6 +205,18 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	return retval;
 }
 
+static void qc_release(struct usb_serial *serial)
+{
+	struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
+
+	dbg("%s", __func__);
+
+	/* Call usb_wwan release & free the private data allocated in qcprobe */
+	usb_wwan_release(serial);
+	usb_set_serial_data(serial, NULL);
+	kfree(priv);
+}
+
 static struct usb_serial_driver qcdevice = {
 	.driver = {
 		.owner     = THIS_MODULE,
@@ -222,7 +234,7 @@ static struct usb_serial_driver qcdevice = {
 	.chars_in_buffer     = usb_wwan_chars_in_buffer,
 	.attach		     = usb_wwan_startup,
 	.disconnect	     = usb_wwan_disconnect,
-	.release	     = usb_wwan_release,
+	.release	     = qc_release,
 #ifdef CONFIG_PM
 	.suspend	     = usb_wwan_suspend,
 	.resume		     = usb_wwan_resume,
#3 lore raw

PATCH 2/3 Resend : Fix memory leak in qcserial driver

In reply to Greg KH

Patch 2 of 3, addresses the problem where serial->private can end up pointing to freed memory in the event qcprobe fails & returns -ENODEV

Original description:
3 - Don't assign serial->private when doing the kzalloc or serial->private ends up pointing to freed memory in the event we return -ENODEV, instead call usb_set_serial_data(serial, data) at the end of the function, and only have one return-point.

drivers/usb/serial/qcserial.c +8 -6
index 6e3b933..0463dab 100644
@@ -111,7 +111,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	ifnum = intf->desc.bInterfaceNumber;
 	dbg("This Interface = %d", ifnum);
 
-	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
+	data = kzalloc(sizeof(struct usb_wwan_intf_private),
 					 GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -134,8 +134,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 		    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
 			dbg("QDL port found");
 
-			if (serial->interface->num_altsetting == 1)
-				return 0;
+			if (serial->interface->num_altsetting == 1) {
+				retval = 0; /* Success */
+				break;
+			}
 
 			retval = usb_set_interface(serial->dev, ifnum, 1);
 			if (retval < 0) {
@@ -145,7 +147,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		}
 		break;
 
@@ -177,7 +178,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		} else if (ifnum==3) {
 			/*
 			 * NMEA (serial line 9600 8N1)
@@ -199,9 +199,11 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 		dev_err(&serial->dev->dev,
 			"unknown number of interfaces: %d\n", nintf);
 		kfree(data);
-		return -ENODEV;
+		retval = -ENODEV;
 	}
 
+	/* Set serial->private may be null if -ENODEV */
+	usb_set_serial_data(serial, data);
 	return retval;
 }
 
#4 lore raw

Re: [GIT PATCH 2/3] Resend : Fix memory leak in qcserial driver

Hello.

On 28-03-2011 21:38, Steven Hardy wrote:

Posting all 3 patches having the same sucject is not a good idea.

Quoted 1 line

Patch 2 of 3, addresses the problem where serial->private can end up pointing to freed memory in the event qcprobe fails & returns -ENODEV

You still didn't wrap the changelog text properly.

Quoted 2 lines

Original description:
3 - Don't assign serial->private when doing the kzalloc or serial->private ends up pointing to freed memory in the event we return -ENODEV, instead call usb_set_serial_data(serial, data) at the end of the function, and only have one return-point.

WBR, Sergei

#5 lore raw

PATCH 2/3 Resend : Fix memory leak in qcserial driver

In reply to Greg KH

Second draft of patch #2, this addresses the review comments made by Aristeu Rozanski, now usb_set_serial_data() is only called when we are not returning -ENODEV

Original description:
Don't assign serial->private when doing the kzalloc or serial->private ends up pointing to freed memory in the event we return -ENODEV, instead call usb_set_serial_data(serial, data) at the end of the function, and only have one return-point.

drivers/usb/serial/qcserial.c +9 -6
index 6e3b933..b9b97ad 100644
@@ -111,7 +111,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	ifnum = intf->desc.bInterfaceNumber;
 	dbg("This Interface = %d", ifnum);
 
-	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
+	data = kzalloc(sizeof(struct usb_wwan_intf_private),
 					 GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -134,8 +134,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 		    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
 			dbg("QDL port found");
 
-			if (serial->interface->num_altsetting == 1)
-				return 0;
+			if (serial->interface->num_altsetting == 1) {
+				retval = 0; /* Success */
+				break;
+			}
 
 			retval = usb_set_interface(serial->dev, ifnum, 1);
 			if (retval < 0) {
@@ -145,7 +147,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		}
 		break;
 
@@ -177,7 +178,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		} else if (ifnum==3) {
 			/*
 			 * NMEA (serial line 9600 8N1)
@@ -199,9 +199,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 		dev_err(&serial->dev->dev,
 			"unknown number of interfaces: %d\n", nintf);
 		kfree(data);
-		return -ENODEV;
+		retval = -ENODEV;
 	}
 
+	/* Set serial->private if not returning -ENODEV */
+	if ( retval != -ENODEV )
+		usb_set_serial_data(serial, data);
 	return retval;
 }
#6 lore raw

Re: [GIT PATCH 2/3 (2nd draft)] Resend : Fix memory leak in qcserial driver

Hello.

Quoted 1 line · Steven Hardy

Second draft of patch #2, this addresses the review comments made by Aristeu Rozanski, now usb_set_serial_data() is only called when we are not returning -ENODEV

Such comments should be put under --- tearline (which should appear under
your signoff). Otherwise Greg will have to hand edit them out of your patch.

Quoted 1 line

Original description:

Omit that please.

Quoted 1 line

Don't assign serial->private when doing the kzalloc or serial->private ends up pointing to freed memory in the event we return -ENODEV, instead call usb_set_serial_data(serial, data) at the end of the function, and only have one return-point.

Still not properly wrapped.

Quoted 7 lines
drivers/usb/serial/qcserial.c +0 -0
index 6e3b933..b9b97ad 100644

[...]

drivers/usb/serial/qcserial.c static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) · line 206

Quoted 10 lines
drivers/usb/serial/qcserial.c +3 -1
@@ -199,9 +199,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
  		dev_err(&serial->dev->dev,
  			"unknown number of interfaces: %d\n", nintf);
  		kfree(data);
-		return -ENODEV;
+		retval = -ENODEV;
  	}
 
+	/* Set serial->private if not returning -ENODEV */
+	if ( retval != -ENODEV )

No spaces after ( and before ) allowed.

WBR, Sergei

#7 lore raw

PATCH 1/3 usb: Fix qcserial memory leak on rmmod

qcprobe function allocates serial->private but this is never freed, this patch adds a new function qc_release() which frees serial->private, after calling usb_wwan_release

---
Repost of qcserial patches posted last week, hopefully addresses review comments and email-patch-format issues

 drivers/usb/serial/qcserial.c |   14 +++++++++++++-
 1 files changed, 13 insertions(+), 1 deletions(-)
drivers/usb/serial/qcserial.c +13 -1
index 8858201..6e3b933 100644
@@ -205,6 +205,18 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	return retval;
 }
 
+static void qc_release(struct usb_serial *serial)
+{
+	struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
+
+	dbg("%s", __func__);
+
+	/* Call usb_wwan release & free the private data allocated in qcprobe */
+	usb_wwan_release(serial);
+	usb_set_serial_data(serial, NULL);
+	kfree(priv);
+}
+
 static struct usb_serial_driver qcdevice = {
 	.driver = {
 		.owner     = THIS_MODULE,
@@ -222,7 +234,7 @@ static struct usb_serial_driver qcdevice = {
 	.chars_in_buffer     = usb_wwan_chars_in_buffer,
 	.attach		     = usb_wwan_startup,
 	.disconnect	     = usb_wwan_disconnect,
-	.release	     = usb_wwan_release,
+	.release	     = qc_release,
 #ifdef CONFIG_PM
 	.suspend	     = usb_wwan_suspend,
 	.resume		     = usb_wwan_resume,
Signature · 1 line
1.7.1
#8 lore raw

PATCH 2/3 usb: qcserial avoid pointing to freed memory

Rework the qcprobe logic such that serial->private is not set when qcprobe exits with -ENODEV, otherwise serial->private will point to freed memory on -ENODEV

---
Repost of qcserial patches posted last week, hopefully addresses review comments and email-patch-format issues

 drivers/usb/serial/qcserial.c |   15 +++++++++------
 1 files changed, 9 insertions(+), 6 deletions(-)
drivers/usb/serial/qcserial.c +9 -6
index 6e3b933..cd63864 100644
@@ -111,7 +111,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	ifnum = intf->desc.bInterfaceNumber;
 	dbg("This Interface = %d", ifnum);
 
-	data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private),
+	data = kzalloc(sizeof(struct usb_wwan_intf_private),
 					 GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
@@ -134,8 +134,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 		    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
 			dbg("QDL port found");
 
-			if (serial->interface->num_altsetting == 1)
-				return 0;
+			if (serial->interface->num_altsetting == 1) {
+				retval = 0; /* Success */
+				break;
+			}
 
 			retval = usb_set_interface(serial->dev, ifnum, 1);
 			if (retval < 0) {
@@ -145,7 +147,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		}
 		break;
 
@@ -177,7 +178,6 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 				retval = -ENODEV;
 				kfree(data);
 			}
-			return retval;
 		} else if (ifnum==3) {
 			/*
 			 * NMEA (serial line 9600 8N1)
@@ -199,9 +199,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 		dev_err(&serial->dev->dev,
 			"unknown number of interfaces: %d\n", nintf);
 		kfree(data);
-		return -ENODEV;
+		retval = -ENODEV;
 	}
 
+	/* Set serial->private if not returning -ENODEV */
+	if (retval != -ENODEV)
+		usb_set_serial_data(serial, data);
 	return retval;
 }
 
Signature · 1 line
1.7.1
#9 lore raw

PATCH 3/3 usb: qcserial add missing errorpath kfrees

In reply to Steven Hardy

There are two -ENODEV error paths in qcprobe where the allocated private data is not freed, this patch adds the two missing kfrees to avoid leaking memory on the error path

---
Repost of qcserial patches posted last week, hopefully addresses review comments and email-patch-format issues

 drivers/usb/serial/qcserial.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/usb/serial/qcserial.c +2 -0
index cd63864..54a9dab 100644
@@ -167,6 +167,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
+				kfree(data);
 			}
 		} else if (ifnum == 2) {
 			dbg("Modem port found");
@@ -191,6 +192,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
+				kfree(data);
 			}
 		}
 		break;
Signature · 1 line
1.7.1
#10 lore raw

Re: [GIT PATCH 2/3 (2nd draft)] Resend : Fix memory leak in qcserial driver

In reply to Steven Hardy

drivers/usb/serial/qcserial.c static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) · line 206

Quoted 2 lines · Steven Hardy
drivers/usb/serial/qcserial.c +2 -0
+	/* Set serial->private if not returning -ENODEV */
+	if ( retval != -ENODEV )

^ ^
coding style

drivers/usb/serial/qcserial.c static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) · line 209

Quoted 3 lines
drivers/usb/serial/qcserial.c +1 -0
+		usb_set_serial_data(serial, data);
 	return retval;
 }

the rest looks good to me.

Signature · 1 line
Aristeu
#11 lore raw

PATCH 3/3 Resend : Fix memory leak in qcserial driver

In reply to Greg KH

Patch 3 of 3, this simply adds a couple of missing free's in the error path:

Original description:
2 - Ensure that the serial->private data is freed in the event of the probe failing and returning -ENODEV. This error-path leak is less likely but still possible, it was discussed previously but not actually fixed AFAICS: http://kerneltrap.org/mailarchive/linux-kernel/2010/6/14/4582980/thread, http://lkml.org/lkml/2010/6/20/234

drivers/usb/serial/qcserial.c +2 -0
index 0463dab..6219fce 100644
@@ -167,6 +167,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
+				kfree(data);
 			}
 		} else if (ifnum == 2) {
 			dbg("Modem port found");
@@ -191,6 +192,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 					"Could not set interface, error %d\n",
 					retval);
 				retval = -ENODEV;
+				kfree(data);
 			}
 		}
 		break;
#12 lore raw
In reply to Steven Hardy

drivers/usb/serial/qcserial.c static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) · line 210

Quoted 13 lines · Steven Hardy
drivers/usb/serial/qcserial.c +3 -1
@@ -198,13 +200,27 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 	default:
 		dev_err(&serial->dev->dev,
 			"unknown number of interfaces: %d\n", nintf);
+		retval = -ENODEV;
 		kfree(data);
-		return -ENODEV;
 	}
 
+	/* Set serial->private may be null if -ENODEV */
+	usb_set_serial_data(serial, data);
 	return retval;
 }

when there's a -ENODEV, kfree() is called but the now invalid address is set by usb_set_serial_data() anyway. am I missing something here?

Signature · 1 line
Aristeu
#13 lore raw
Quoted 5 lines · Aristeu Rozanski

drivers/usb/serial/qcserial.c static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) · line 210

Quoted 3 lines
drivers/usb/serial/qcserial.c +1 -0
+	usb_set_serial_data(serial, data);
 	return retval;
 }

when there's a -ENODEV, kfree() is called but the now invalid address is set by usb_set_serial_data() anyway. am I missing something here?

The intention here is that since data should be NULL after the kfree, we're simply setting serial->private to NULL.

I can add a conditional to avoid calling usb_set_serial_data() for -ENODEV if it's deemed cleaner or more readable.

Thanks for the comments,

Steve

#14 lore raw
Quoted 8 lines · Steven Hardy
Quoted 5 lines · Aristeu Rozanski

drivers/usb/serial/qcserial.c static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) · line 210

Quoted 3 lines
drivers/usb/serial/qcserial.c +1 -0
+	usb_set_serial_data(serial, data);
 	return retval;
 }

when there's a -ENODEV, kfree() is called but the now invalid address is set by usb_set_serial_data() anyway. am I missing something here?

The intention here is that since data should be NULL after the kfree, we're simply setting serial->private to NULL.

kfree(data) won't make data == NULL. it'll free whatever address data has. data will still have the same (now stale) address. you need to explicitely make data = NULL if you want that behavior.

Signature · 1 line
Aristeu
#15 lore raw
Quoted 3 lines · Aristeu Rozanski

kfree(data) won't make data == NULL. it'll free whatever address data has. data will still have the same (now stale) address. you need to explicitely make data = NULL if you want that behavior.

Of course, sorry I should have remembered that, too much scripting lately's caused some brain-rot :)

I will resend a revised patch.

Thanks,

Steve