// An ioremap is not matched by an iounmap before an error return.
//
// Confidence: Moderate
// Copyright: (C) Gilles Muller, Julia Lawall, EMN, INRIA, DIKU.  GPLv2.
// URL: https://coccinelle.gitlabpages.inria.fr/website/rules/iounmap_check.html
// Options:

@r@
local idexpression n;
position p1;
@@

n = ioremap@p1(...)

// find the missing returns
@t exists@
local idexpression n;
statement S1;
expression E;
expression *ptr != NULL;
type T;
position r.p1,p2;
@@

(
if ((n = ioremap@p1(...)) == NULL) S1
|
n = ioremap@p1(...)
)
... when != iounmap((T)n)
    when != if (...) { <+... iounmap((T)n) ...+> }
    when != true n == NULL  || ...
    when != n = (T)E
    when != E = n
(
  return \(0\|<+...n...+>\|ptr\);
|
return@p2 ...;
)

// find the ones with no inconsistent paths
@s@
local idexpression n;
statement S1,S2;
expression E,E1;
expression *ptr != NULL;
type T,T1;
identifier l1,l2;
position r.p1;
@@

(
if ((n = ioremap@p1(...)) == NULL) S1
|
n = ioremap@p1(...)
)
<... when != iounmap((T)n)
    when != if (...) { <+... iounmap((T)n) ...+> }
    when != true n == NULL  || ...
    when != n = (T)E
    when != E = n
    when != goto l1;
if (n == NULL || ...) S2
...>
(
  return \(0\|<+...n...+>\|ptr\);
|
+ iounmap(n);
return ...;
|
iounmap(n);
|
n = (T1)E1
|
E1 = n
|
goto l2;
)

@script:python depends on !s@
p1 << r.p1;
p2 << t.p2;
@@

print "* file: %s ioremap %s return %s" % (p1[0].file,p1[0].line,p2[0].line)