coccinelle: catchup on memory allocation functions
cover coccinelle: catchup on memory allocation functions
Hi,
Please find few patches that remove coccicheck's blindness regarding the following functions:
- kzfree()
- krealloc()
- __krealloc()
- devm_kmalloc()
- devm_kvasprintf()
- devm_kasprintf()
- devm_kmalloc_array()
- devm_kcalloc()
- devm_kstrdup()
- devm_kmemdup()
- devm_get_free_pages()
- free_pages()
- free_page()
I've ran coccicheck on drivers/staging and found no new issue, which is great, but that questions those patches' usefulness, YMMV.
Regards.
Yann Droneaud (3):
coccinelle: also catch kzfree() issues
coccinelle: recognize more devm_* memory allocation functions
coccinelle: catch krealloc() on devm_*() allocated memory
scripts/coccinelle/free/devm_free.cocci | 26 ++++++++++++++++++++++++++ scripts/coccinelle/free/kfree.cocci | 3 +++ scripts/coccinelle/free/kfreeaddr.cocci | 6 +++++- 3 files changed, 34 insertions(+), 1 deletion(-)
Signature · 1 line
2.5.0
PATCH 1/3 coccinelle: also catch kzfree() issues
Since commit 3ef0e5ba4673 ('slab: introduce kzfree()'), kfree() is no more the only function to be considered.
--- scripts/coccinelle/free/devm_free.cocci | 2 ++ scripts/coccinelle/free/kfree.cocci | 3 +++ scripts/coccinelle/free/kfreeaddr.cocci | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-)
scripts/coccinelle/free/devm_free.cocci +2 -0
@@ -48,6 +48,8 @@ position p; ( * kfree at p(x) | +* kzfree at p(x) +| * free_irq at p(x) | * iounmap at p(x)
scripts/coccinelle/free/kfree.cocci +3 -0
@@ -16,6 +16,7 @@ virtual org virtual report @free@ +identifier kfree =~ "kz?free"; expression E; position p1; @@
@@ -54,6 +55,7 @@ position p; sizeof(<+...E@p...+>) @loop exists@ +identifier kfree =~ "kz?free"; expression E; identifier l; position ok;
@@ -67,6 +69,7 @@ while (1) { ... } @r exists@ +identifier kfree =~ "kz?free"; expression free.E, subE<=free.E, E2; expression E1; iterator iter;
scripts/coccinelle/free/kfreeaddr.cocci +5 -1
@@ -16,7 +16,11 @@ identifier f; position p; @@ +( * kfree@p(&e->f) +| +* kzfree at p(&e->f) +) @script:python depends on org@ p << r.p;
@@ -28,5 +32,5 @@ cocci.print_main("kfree",p) p << r.p; @@ -msg = "ERROR: kfree of structure field" +msg = "ERROR: invalid free of structure field" coccilib.report.print_report(p[0],msg)
Signature · 1 line
2.5.0
Re: [PATCH 1/3] coccinelle: also catch kzfree() issues
Quoted 29 lines · Yann Droneaud
Since commit
3ef0e5ba4673('slab: introducekzfree()'),kfree()is no more the only function to be considered.Cc Johannes Weiner <[email protected]>Signed-off-by Yann Droneaud <[email protected]>--- scripts/coccinelle/free/devm_free.cocci | 2 ++ scripts/coccinelle/free/kfree.cocci | 3 +++ scripts/coccinelle/free/kfreeaddr.cocci | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-)scripts/coccinelle/free/devm_free.cocci +2
-0@@ -48,6 +48,8 @@ position p; ( * kfree at p(x) | +* kzfree at p(x) +| * free_irq at p(x) | * iounmap at p(x)scripts/coccinelle/free/kfree.cocci +0
-0
scripts/coccinelle/free/kfree.cocci virtual org · line 19
Quoted 4 lines
scripts/coccinelle/free/kfree.cocci +1
-0@@ -16,6 +16,7 @@ virtual org virtual report @free@ +identifier kfree =~ "kz?free";
Thanks for the suggestions. However, the regular expression is not such a good idea. Coccinelle doesn't make any optimizations based on regulat expressions. It would be better to put a disjunction with kfree and kzfree explicitly, as in the other cases.
julia
Quoted 46 lines
scripts/coccinelle/free/kfree.cocci +2
-0expression E; position p1; @@@@ -54,6 +55,7 @@ position p; sizeof(<+...E@p...+>) @loop exists@ +identifier kfree =~ "kz?free"; expression E; identifier l; position ok;@@ -67,6 +69,7 @@ while (1) { ... } @r exists@ +identifier kfree =~ "kz?free"; expression free.E, subE<=free.E, E2; expression E1; iterator iter;scripts/coccinelle/free/kfreeaddr.cocci +5
-2@@ -16,7 +16,11 @@ identifier f; position p; @@ +( * kfree at p(&e->f) +| +* kzfree at p(&e->f) +) @script:python depends on org@ p << r.p;@@ -28,5 +32,5 @@ cocci.print_main("kfree",p) p << r.p; @@ -msg = "ERROR: kfree of structure field" +msg = "ERROR: invalid free of structure field" coccilib.report.print_report(p[0],msg) --2.5.0
Re: coccinelle: also catch kzfree() issues
Quoted 5 lines
Quoted 2 lines
@free@
+identifier kfree =~ "kz?free";Thanks for the suggestions. However, the regular expression is not such a good idea.
How much is such a SmPL constraint still usable then?
Quoted 1 line
Coccinelle doesn't make any optimizations based on regulat expressions.
Where can your software optimise the source code search?
Quoted 2 lines
It would be better to put a disjunction with kfree and kzfree explicitly, as in the other cases.
What are the circumstances for corresponding benefits?
Regards,
Markus
Re: coccinelle: also catch kzfree() issues
Quoted 6 lines · SF Markus Elfring
Quoted 5 lines
Quoted 2 lines
@free@
+identifier kfree =~ "kz?free";Thanks for the suggestions. However, the regular expression is not such a good idea.
Quoted 6 lines
How much is such a SmPL constraint still usable then?
Quoted 1 line
Coccinelle doesn't make any optimizations based on regulat expressions.
Where can your software optimise the source code search?
When the name appears explicitly in the matching code, Coccinelle will parse and process only files that contain that name.
julia
Quoted 10 lines
Quoted 4 lines
It would be better to put a disjunction with kfree and kzfree explicitly, as in the other cases.
What are the circumstances for corresponding benefits?
Regards,
Markus
Re: coccinelle: also catch kzfree() issues
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
Coccinelle doesn't make any optimizations based on regulat expressions.
Where can your software optimise the source code search?
When the name appears explicitly in the matching code, Coccinelle will parse and process only files that contain that name.
Does your software perform any file filtering on a passed selection under special circumstances?
Regards,
Markus
PATCH 1/3 coccinelle: also catch kzfree() issues
In reply to Julia LawallSince commit 3ef0e5ba4673 ('slab: introduce kzfree()'), kfree() is no more the only function to be considered.
In particular, kzfree() must not be called on memory allocated through devm_*() functions.
---
Hi Julia,
As you suggested, I've use disjunctions instead of regular expressions (which I managed to use incorrectly: eg. without ^...$ they catch other functions than kfree(), such as kfree_skb()).
I've think we should also catch krealloc(, size), where size is 0, but it's beyond my understanding of coccinelle if size is not a plain 0 constant.
Perhaps you could help me for this one.
Regards.
scripts/coccinelle/free/devm_free.cocci | 2 ++ scripts/coccinelle/free/kfree.cocci | 18 +++++++++++++++--- scripts/coccinelle/free/kfreeaddr.cocci | 6 +++++- 3 files changed, 22 insertions(+), 4 deletions(-)
scripts/coccinelle/free/devm_free.cocci +2 -0
@@ -48,6 +48,8 @@ position p; ( * kfree at p(x) | +* kzfree at p(x) +| * free_irq at p(x) | * iounmap at p(x)
scripts/coccinelle/free/kfree.cocci +15 -3
@@ -20,7 +20,11 @@ expression E; position p1; @@ -kfree at p1(E) +( +* kfree at p1(E) +| +* kzfree at p1(E) +) @print expression@ constant char [] c;
@@ -60,7 +64,11 @@ position ok; @@ while (1) { ... - kfree at ok(E) +( +* kfree at ok(E) +| +* kzfree at ok(E) +) ... when != break; when != goto l; when forall
@@ -74,7 +82,11 @@ statement S; position free.p1!=loop.ok,p2!={print.p,sz.p}; @@ -kfree at p1(E,...) +( +* kfree at p1(E,...) +| +* kzfree at p1(E,...) +) ... ( iter(...,subE,...) S // no use
scripts/coccinelle/free/kfreeaddr.cocci +5 -1
@@ -16,7 +16,11 @@ identifier f; position p; @@ +( * kfree at p(&e->f) +| +* kzfree at p(&e->f) +) @script:python depends on org@ p << r.p;
@@ -28,5 +32,5 @@ cocci.print_main("kfree",p) p << r.p; @@ -msg = "ERROR: kfree of structure field" +msg = "ERROR: invalid free of structure field" coccilib.report.print_report(p[0],msg)
Signature · 1 line
2.5.0
Re: [PATCHv1 1/3] coccinelle: also catch kzfree() issues
Quoted 16 lines · Yann Droneaud
Since commit
3ef0e5ba4673('slab: introducekzfree()'),kfree()is no more the only function to be considered.In particular,
kzfree()must not be called on memory allocated through devm_*() functions.Cc Johannes Weiner <[email protected]>Signed-off-by Yann Droneaud <[email protected]>---
Hi Julia,As you suggested, I've use disjunctions instead of regular expressions (which I managed to use incorrectly: eg. without ^...$ they catch other functions than
kfree(), such askfree_skb()).
Quoted 5 lines
I've think we should also catch
krealloc(, size), where size is 0, but it's beyond my understanding of coccinelle if size is not a plain 0 constant.Perhaps you could help me for this one.
Do you have some examples? Coccinelle is not very good at tracking values. You can say something like:
size = 0
... when != size = ekrealloc(...,size)
I don't know if that would be useful in practice though.
Quoted 90 lines
Regards.
scripts/coccinelle/free/devm_free.cocci | 2 ++ scripts/coccinelle/free/kfree.cocci | 18 +++++++++++++++--- scripts/coccinelle/free/kfreeaddr.cocci | 6 +++++- 3 files changed, 22 insertions(+), 4 deletions(-)scripts/coccinelle/free/devm_free.cocci +2
-0@@ -48,6 +48,8 @@ position p; ( * kfree at p(x) | +* kzfree at p(x) +| * free_irq at p(x) | * iounmap at p(x)scripts/coccinelle/free/kfree.cocci +15
-3@@ -20,7 +20,11 @@ expression E; position p1; @@ -kfree at p1(E) +( +* kfree at p1(E) +| +* kzfree at p1(E) +) @print expression@ constant char [] c;@@ -60,7 +64,11 @@ position ok; @@ while (1) { ... - kfree at ok(E) +( +* kfree at ok(E) +| +* kzfree at ok(E) +) ... when != break; when != goto l; when forall@@ -74,7 +82,11 @@ statement S; position free.p1!=loop.ok,p2!={print.p,sz.p}; @@ -kfree at p1(E,...) +( +* kfree at p1(E,...) +| +* kzfree at p1(E,...) +) ( iter(...,subE,...) S // no usescripts/coccinelle/free/kfreeaddr.cocci +5
-2@@ -16,7 +16,11 @@ identifier f; position p; @@ +( * kfree at p(&e->f) +| +* kzfree at p(&e->f) +) @script:python depends on org@ p << r.p;@@ -28,5 +32,5 @@ cocci.print_main("kfree",p) p << r.p; @@ -msg = "ERROR: kfree of structure field" +msg = "ERROR: invalid free of structure field" coccilib.report.print_report(p[0],msg) --2.5.0
Re: [PATCHv1 1/3] coccinelle: also catch kzfree() issues
Le lundi 22 f?vrier 2016 ? 09:20 -0500, Julia Lawall a ?crit?:
Quoted 18 lines · Yann Droneaud
Quoted 17 lines
Since commit
3ef0e5ba4673('slab: introducekzfree()'),kfree()is no more the only function to be considered.In particular,
kzfree()must not be called on memory allocated through devm_*() functions.Cc Johannes Weiner <[email protected]>Signed-off-by Yann Droneaud <[email protected]>---
Hi Julia,As you suggested, I've use disjunctions instead of regular expressions (which I managed to use incorrectly: eg. without ^...$ they catch other functions than
kfree(), such askfree_skb()).
Quoted 7 lines
Quoted 5 lines
I've think we should also catch
krealloc(, size), where size is 0, but it's beyond my understanding of coccinelle if size is not a plain 0 constant.Perhaps you could help me for this one.
Do you have some examples?
I don't have any real world examples (hopefully) and I don't think it's going to catch issues, as it's unlikely someone would write krealloc(ptr, 0) instead of kfree().
Quoted 7 lines
? Coccinelle is not very good at tracking
values.? You can say something like:size = 0
... when != size = ekrealloc(...,size)
It works for the most simple cases I can think of. Thanks a lot !
Quoted 2 lines
I don't know if that would be useful in practice though.
It will be difficult to shoehorn such construct in the dijunctions added here.
Perhaps we could add a new cocci rules file that would translate such call to krealloc() to kfree():
@@
expression e;
expression p;
identifier size;
@@
? size = 0
? ... when != size = e
-??krealloc(p,size)
+??kfree(p)
@@
expression p;
@@
-??krealloc(p, 0)
+??kfree(p)
But I'm not sure it worth it.
Quoted 86 lines
Review
Quoted 8 lines
Regards.
? scripts/coccinelle/free/devm_free.cocci |? 2 ++ ? scripts/coccinelle/free/kfree.cocci???? | 18 +++++++++++++++--- ? scripts/coccinelle/free/kfreeaddr.cocci |? 6 +++++-? 3 files changed, 22 insertions(+), 4 deletions(-)
(quoted diff) +0
-0
b/scripts/coccinelle/free/devm_free.cocciQuoted 12 lines
index
3d9349012bb3..83c03adec1c5100644scripts/coccinelle/free/devm_free.cocci +0
-0@@ -48,6 +48,8 @@ position p;? (
? * kfree at p(x)
? |
+* kzfree at p(x)
+|
? *free_irqat p(x)
? |
? * iounmap at p(x)Review
Quoted 1 line
(quoted diff) +0
-0
b/scripts/coccinelle/free/kfree.cocciQuoted 42 lines
index
577b78056990..ac438da4fd7b100644scripts/coccinelle/free/kfree.cocci +0
-0@@ -20,7 +20,11 @@ expression E; ? position p1;? @@
scripts/coccinelle/free/kfree.cocci +5
-1-kfree at p1(E) +( +* kfree at p1(E) +| +* kzfree at p1(E) +)? @print expression@
? constant char [] c;scripts/coccinelle/free/kfree.cocci +0
-0@@ -60,7 +64,11 @@ position ok;? @@
? while (1) { ...
-? kfree at ok(E)scripts/coccinelle/free/kfree.cocci +5
-0+( +* kfree at ok(E) +| +* kzfree at ok(E) +)??? ... when != break;
??????? when != goto l;
??????? when forallscripts/coccinelle/free/kfree.cocci +0
-0@@ -74,7 +82,11 @@ statement S; ? position free.p1!=loop.ok,p2!={print.p,sz.p};? @@
scripts/coccinelle/free/kfree.cocci +5
-1-kfree at p1(E,...) +( +* kfree at p1(E,...) +| +* kzfree at p1(E,...) +)? ...
? (
??iter(...,subE,...)S // no useReview
Quoted 1 line
(quoted diff) +0
-0
b/scripts/coccinelle/free/kfreeaddr.cocciQuoted 19 lines
index
ce8aacc314cb..d46063b1db8b100644scripts/coccinelle/free/kfreeaddr.cocci +0
-0@@ -16,7 +16,11 @@ identifier f; ? position p;? @@
+(
? * kfree atp(&e->f)
+|scripts/coccinelle/free/kfreeaddr.cocci +2
-0+* kzfree at p(&e->f) +)? @script:python depends on org@
? p << r.p;scripts/coccinelle/free/kfreeaddr.cocci +0
-0@@ -28,5 +32,5 @@ cocci.print_main("kfree",p) ? p << r.p;? @@
Quoted 7 lines
Quoted 7 lines
scripts/coccinelle/free/kfreeaddr.cocci +1
-1-msg = "ERROR: kfree of structure field" +msg = "ERROR: invalid free of structure field"?
coccilib.report.print_report(p[0],msg)
--
2.5.0
Regards.
--?
Yann Droneaud
OPTEYA
PATCH 2/3 coccinelle: recognize more devm_* memory allocation functions
In reply to Yann DroneaudUpdates free/devm_free.cocci to recognize functions added by:
- commit 64c862a839a8 ('devres: add kernel standard devm_k.alloc functions')
- commit e31108cad3de ('devres: introduce API "devm_kstrdup"')
- commit 3046365bb470 ('devres: introduce API "devm_kmemdup')
- commit 43339bed7010 ('devres: Add devm_get_free_pages API')
- commit 75f2a4ead5d5 ('devres: Add devm_kasprintf and devm_kvasprintf API')
See also Documentation/driver-model/devres.txt
--- scripts/coccinelle/free/devm_free.cocci | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
scripts/coccinelle/free/devm_free.cocci +20 -0
@@ -29,8 +29,24 @@ expression x; @@ ( + x = devm_kmalloc(...) +| + x = devm_kvasprintf(...) +| + x = devm_kasprintf(...) +| x = devm_kzalloc(...) | + x = devm_kmalloc_array(...) +| + x = devm_kcalloc(...) +| + x = devm_kstrdup(...) +| + x = devm_kmemdup(...) +| + x = devm_get_free_pages(...) +| x = devm_request_irq(...) | x = devm_ioremap(...)
@@ -50,6 +66,10 @@ position p; | * kzfree at p(x) | +* free_pages at p(x, ...) +| +* free_page at p(x) +| * free_irq at p(x) | * iounmap at p(x)
Signature · 1 line
2.5.0
Re: [PATCH 2/3] coccinelle: recognize more devm_* memory allocation functions
Quoted 10 lines · Yann Droneaud
Updates
free/devm_free.coccito recognize functions added by:- commit
64c862a839a8('devres: add kernel standard devm_k.alloc functions')
- commite31108cad3de('devres: introduce API "devm_kstrdup"')
- commit3046365bb470('devres: introduce API "devm_kmemdup')
- commit43339bed7010('devres: Adddevm_get_free_pagesAPI')
- commit75f2a4ead5d5('devres: Adddevm_kasprintfanddevm_kvasprintfAPI')See also
Documentation/driver-model/devres.txt
Quoted 9 lines
Cc Joe Perches <[email protected]>Cc Manish Badarkhe <[email protected]>Cc Srinivas Pandruvada <[email protected]>Cc Eli Billauer <[email protected]>Cc Himangi Saraogi <[email protected]>Cc Geert Uytterhoeven <[email protected]>Cc Wolfram Sang <[email protected]>Cc Daniel Thompson <[email protected]>Signed-off-by Yann Droneaud <[email protected]>
Quoted 48 lines
--- scripts/coccinelle/free/devm_free.cocci | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)scripts/coccinelle/free/devm_free.cocci +20
-1@@ -29,8 +29,24 @@ expression x; @@ ( + x = devm_kmalloc(...) +| + x = devm_kvasprintf(...) +| + x = devm_kasprintf(...) +| x = devm_kzalloc(...) | + x = devm_kmalloc_array(...) +| + x = devm_kcalloc(...) +| + x = devm_kstrdup(...) +| + x = devm_kmemdup(...) +| + x = devm_get_free_pages(...) +| x = devm_request_irq(...) | x = devm_ioremap(...)@@ -50,6 +66,10 @@ position p; | * kzfree at p(x) | +* free_pages at p(x, ...) +| +* free_page at p(x) +| * free_irq at p(x) | * iounmap at p(x) --2.5.0
PATCH 3/3 coccinelle: catch krealloc() on devm_*() allocated memory
In reply to Yann Droneaudkrealloc() must not be used against devm_*() allocated memory regions:
- if a bigger memory is to be allocated, krealloc() and __krealloc() could return a different pointer than the one given to them, creating a memory region which is not managed, thus it will not be automatically released on device removal.
- if a bigger memory is to be allocated, krealloc() could kfree() the managed memory region which is passed to it. The old pointer is left registered as a resource for the device. On device removal, this dangling pointer will be used and an unrelated memory region could be released.
- if the requested size is equal to 0, krealloc() can also just behave like kfree(). Here too, the old pointer is kept associated with the device. On device removal, this invalid pointer will be used and an unrelated memory region could be released.
For all these reasons, krealloc() must not be used on a pointer returned by devm_*() functions.
--- scripts/coccinelle/free/devm_free.cocci | 4 ++++ 1 file changed, 4 insertions(+)
scripts/coccinelle/free/devm_free.cocci +4 -0
@@ -66,6 +66,10 @@ position p; | * kzfree at p(x) | +* __krealloc at p(x, ...) +| +* krealloc at p(x, ...) +| * free_pages at p(x, ...) | * free_page at p(x)
Signature · 1 line
2.5.0
Re: [PATCH 3/3] coccinelle: catch krealloc() on devm_*() allocated memory
Quoted 21 lines · Yann Droneaud
krealloc()must not be used against devm_*() allocated memory regions:- if a bigger memory is to be allocated,
krealloc()and__krealloc()could return a different pointer than the one given to them, creating a memory region which is not managed, thus it will not be automatically released on device removal.- if a bigger memory is to be allocated,
krealloc()couldkfree()the managed memory region which is passed to it. The old pointer is left registered as a resource for the device. On device removal, this dangling pointer will be used and an unrelated memory region could be released.- if the requested size is equal to 0,
krealloc()can also just behave likekfree(). Here too, the old pointer is kept associated with the device. On device removal, this invalid pointer will be used and an unrelated memory region could be released.
Quoted 6 lines
For all these reasons,
krealloc()must not be used on a pointer returned by devm_*() functions.Cc Tejun Heo <[email protected]>Cc Pekka Enberg <[email protected]>Signed-off-by Yann Droneaud <[email protected]>
Quoted 23 lines
--- scripts/coccinelle/free/devm_free.cocci | 4 ++++ 1 file changed, 4 insertions(+)scripts/coccinelle/free/devm_free.cocci +4
-1@@ -66,6 +66,10 @@ position p; | * kzfree at p(x) | +* __krealloc at p(x, ...) +| +* krealloc at p(x, ...) +| * free_pages at p(x, ...) | * free_page at p(x) --2.5.0