linux-sparse.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] multiple dereference in function calls
@ 2017-12-21  0:19 Luc Van Oostenryck
  2017-12-21  0:19 ` [PATCH 1/3] add testcases for multiple deref of calls Luc Van Oostenryck
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2017-12-21  0:19 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

In most situations of function type is implicitly
converted to the corresponding pointer.
This pointer can be dereferenced but the implicit
conversion will make it to immediatly decay back
to a pointer. In consequence, in a function call
the function designator can be preceded by an unlimited
number of deref operator ('*').

This series makes it effective.

Luc Van Oostenryck (3):
  add testcases for multiple deref of calls
  avoid unneeded alloc on error path
  dereference of a function is a no-op

 evaluate.c                         | 6 +++++-
 validation/function-pointer-type.c | 3 +++
 validation/linear/call-builtin.c   | 5 ++++-
 validation/linear/call-direct.c    | 5 ++++-
 validation/linear/call-indirect.c  | 4 +++-
 validation/linear/call-inline.c    | 5 ++++-
 validation/sizeof-function.c       | 1 -
 7 files changed, 23 insertions(+), 6 deletions(-)

-- 
2.15.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] add testcases for multiple deref of calls
  2017-12-21  0:19 [PATCH 0/3] multiple dereference in function calls Luc Van Oostenryck
@ 2017-12-21  0:19 ` Luc Van Oostenryck
  2017-12-21  0:19 ` [PATCH 2/3] avoid unneeded alloc on error path Luc Van Oostenryck
  2017-12-21  0:19 ` [PATCH 3/3] dereference of a function is a no-op Luc Van Oostenryck
  2 siblings, 0 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2017-12-21  0:19 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 validation/function-pointer-type.c | 4 ++++
 validation/linear/call-builtin.c   | 6 +++++-
 validation/linear/call-direct.c    | 6 +++++-
 validation/linear/call-indirect.c  | 5 ++++-
 validation/linear/call-inline.c    | 6 +++++-
 5 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/validation/function-pointer-type.c b/validation/function-pointer-type.c
index 8fd792b3b..cb1f59b2a 100644
--- a/validation/function-pointer-type.c
+++ b/validation/function-pointer-type.c
@@ -2,8 +2,12 @@ extern int fun(void);
 
 void fa(void) { int (*f)(void); f = &fun; }
 void f0(void) { int (*f)(void); f = fun; }	// C99,C11 6.3.2.1p4
+void f1(void) { int (*f)(void); f = *fun; }	// C99,C11 6.5.3.2p4
+void f2(void) { int (*f)(void); f = **fun; }	// C99,C11 6.5.3.2p4
+void f3(void) { int (*f)(void); f = ***fun; }	// C99,C11 6.5.3.2p4
 
 /*
  * check-name: type of function pointers
  * check-command: sparse -Wno-decl $file
+ * check-known-to-fail
  */
diff --git a/validation/linear/call-builtin.c b/validation/linear/call-builtin.c
index af0148aa4..b0261e992 100644
--- a/validation/linear/call-builtin.c
+++ b/validation/linear/call-builtin.c
@@ -3,12 +3,16 @@ typedef unsigned int u32;
 u32 ff(u32 a) { return __builtin_popcount(a); }
 
 u32 f0(u32 a) { return (__builtin_popcount)(a); }
+u32 f1(u32 a) { return (*__builtin_popcount)(a); }	// C99,C11 6.5.3.2p4
+u32 f2(u32 a) { return (**__builtin_popcount)(a); }	// C99,C11 6.5.3.2p4
+u32 f3(u32 a) { return (***__builtin_popcount)(a); }	// C99,C11 6.5.3.2p4
 
 /*
  * check-name: builtin calls
  * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
- * check-output-pattern(2): call\..*__builtin_.*, %arg1
+ * check-output-pattern(5): call\..*__builtin_.*, %arg1
  */
diff --git a/validation/linear/call-direct.c b/validation/linear/call-direct.c
index 78321ab02..176bfe229 100644
--- a/validation/linear/call-direct.c
+++ b/validation/linear/call-direct.c
@@ -3,12 +3,16 @@ extern int fun(void);
 int ff(void) { return fun(); }
 
 int f0(void) { return (fun)(); }
+int f1(void) { return (*fun)(); }	// C99,C11 6.5.3.2p4
+int f2(void) { return (**fun)(); }	// C99,C11 6.5.3.2p4
+int f3(void) { return (***fun)(); }	// C99,C11 6.5.3.2p4
 
 /*
  * check-name: direct calls
  * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
- * check-output-pattern(2): call\..* fun
+ * check-output-pattern(5): call\..* fun
  */
diff --git a/validation/linear/call-indirect.c b/validation/linear/call-indirect.c
index f5f2adaf1..d8797b024 100644
--- a/validation/linear/call-indirect.c
+++ b/validation/linear/call-indirect.c
@@ -2,12 +2,15 @@ int gg(int (*fun)(void)) { return fun(); }
 
 int g0(int (*fun)(void)) { return (fun)(); }
 int g1(int (*fun)(void)) { return (*fun)(); }	// C99,C11 6.5.3.2p4
+int g2(int (*fun)(void)) { return (**fun)(); }	// C99,C11 6.5.3.2p4
+int g3(int (*fun)(void)) { return (***fun)(); }	// C99,C11 6.5.3.2p4
 
 /*
  * check-name: indirect calls
  * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
- * check-output-pattern(3): call\..* %arg1
+ * check-output-pattern(5): call\..* %arg1
  */
diff --git a/validation/linear/call-inline.c b/validation/linear/call-inline.c
index 32f32461c..d931a3cba 100644
--- a/validation/linear/call-inline.c
+++ b/validation/linear/call-inline.c
@@ -3,13 +3,17 @@ static inline int fun(void) { return 42; }
 int fi(void) { return fun(); }
 
 int i0(void) { return (fun)(); }
+int i1(void) { return (*fun)(); }		// C99,C11 6.5.3.2p4
+int i2(void) { return (**fun)(); }		// C99,C11 6.5.3.2p4
+int i3(void) { return (***fun)(); }		// C99,C11 6.5.3.2p4
 
 /*
  * check-name: inline calls
  * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
  * check-output-excludes: call
- * check-output-pattern(2): ret\..* \\$42
+ * check-output-pattern(5): ret\..* \\$42
  */
-- 
2.15.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] avoid unneeded alloc on error path
  2017-12-21  0:19 [PATCH 0/3] multiple dereference in function calls Luc Van Oostenryck
  2017-12-21  0:19 ` [PATCH 1/3] add testcases for multiple deref of calls Luc Van Oostenryck
@ 2017-12-21  0:19 ` Luc Van Oostenryck
  2017-12-21  0:19 ` [PATCH 3/3] dereference of a function is a no-op Luc Van Oostenryck
  2 siblings, 0 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2017-12-21  0:19 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

In evaluate_dereference(), a node is allocated but
is not used if there is an error.

Fix this by allocating the node after the error checks.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 evaluate.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/evaluate.c b/evaluate.c
index 6b3e2c257..e6dbe3d8d 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1776,7 +1776,6 @@ static struct symbol *evaluate_dereference(struct expression *expr)
 	if (ctype->type == SYM_NODE)
 		ctype = ctype->ctype.base_type;
 
-	node = alloc_symbol(expr->pos, SYM_NODE);
 	target = ctype->ctype.base_type;
 
 	switch (ctype->type) {
@@ -1784,6 +1783,7 @@ static struct symbol *evaluate_dereference(struct expression *expr)
 		expression_error(expr, "cannot dereference this type");
 		return NULL;
 	case SYM_PTR:
+		node = alloc_symbol(expr->pos, SYM_NODE);
 		node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER;
 		merge_type(node, ctype);
 		break;
@@ -1801,6 +1801,7 @@ static struct symbol *evaluate_dereference(struct expression *expr)
 		 * When an array is dereferenced, we need to pick
 		 * up the attributes of the original node too..
 		 */
+		node = alloc_symbol(expr->pos, SYM_NODE);
 		merge_type(node, op->ctype);
 		merge_type(node, ctype);
 		break;
-- 
2.15.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] dereference of a function is a no-op
  2017-12-21  0:19 [PATCH 0/3] multiple dereference in function calls Luc Van Oostenryck
  2017-12-21  0:19 ` [PATCH 1/3] add testcases for multiple deref of calls Luc Van Oostenryck
  2017-12-21  0:19 ` [PATCH 2/3] avoid unneeded alloc on error path Luc Van Oostenryck
@ 2017-12-21  0:19 ` Luc Van Oostenryck
  2 siblings, 0 replies; 4+ messages in thread
From: Luc Van Oostenryck @ 2017-12-21  0:19 UTC (permalink / raw)
  To: linux-sparse; +Cc: Luc Van Oostenryck

For the '*' operator and functions, the C standard says:
        "If the operand points to a function, the result is a
         function designator; ... If the operand has type
         ‘pointer to type’, the result has type ‘type’".
but also (C11 6.3.2.1p4):
        "(except with 'sizeof' ...) a function designator with type
         ‘function returning type’ is converted to an expression
          that has type ‘pointer to function returning type’".

This means that in dereferencement of a function-designator is
a no-op since the resulting expression is immediately back converted
to a pointer to the function.

The change effectively drop any dereferencement of function types
during their evaluation.

Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
---
 evaluate.c                         | 3 +++
 validation/function-pointer-type.c | 1 -
 validation/linear/call-builtin.c   | 1 -
 validation/linear/call-direct.c    | 1 -
 validation/linear/call-indirect.c  | 1 -
 validation/linear/call-inline.c    | 1 -
 validation/sizeof-function.c       | 1 -
 7 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/evaluate.c b/evaluate.c
index e6dbe3d8d..840f98d3e 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -1782,6 +1782,9 @@ static struct symbol *evaluate_dereference(struct expression *expr)
 	default:
 		expression_error(expr, "cannot dereference this type");
 		return NULL;
+	case SYM_FN:
+		*expr = *op;
+		return expr->ctype;
 	case SYM_PTR:
 		node = alloc_symbol(expr->pos, SYM_NODE);
 		node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER;
diff --git a/validation/function-pointer-type.c b/validation/function-pointer-type.c
index cb1f59b2a..ebc4007ba 100644
--- a/validation/function-pointer-type.c
+++ b/validation/function-pointer-type.c
@@ -9,5 +9,4 @@ void f3(void) { int (*f)(void); f = ***fun; }	// C99,C11 6.5.3.2p4
 /*
  * check-name: type of function pointers
  * check-command: sparse -Wno-decl $file
- * check-known-to-fail
  */
diff --git a/validation/linear/call-builtin.c b/validation/linear/call-builtin.c
index b0261e992..b15113593 100644
--- a/validation/linear/call-builtin.c
+++ b/validation/linear/call-builtin.c
@@ -10,7 +10,6 @@ u32 f3(u32 a) { return (***__builtin_popcount)(a); }	// C99,C11 6.5.3.2p4
 /*
  * check-name: builtin calls
  * check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
diff --git a/validation/linear/call-direct.c b/validation/linear/call-direct.c
index 176bfe229..52f86306b 100644
--- a/validation/linear/call-direct.c
+++ b/validation/linear/call-direct.c
@@ -10,7 +10,6 @@ int f3(void) { return (***fun)(); }	// C99,C11 6.5.3.2p4
 /*
  * check-name: direct calls
  * check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
diff --git a/validation/linear/call-indirect.c b/validation/linear/call-indirect.c
index d8797b024..1275910c4 100644
--- a/validation/linear/call-indirect.c
+++ b/validation/linear/call-indirect.c
@@ -8,7 +8,6 @@ int g3(int (*fun)(void)) { return (***fun)(); }	// C99,C11 6.5.3.2p4
 /*
  * check-name: indirect calls
  * check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
diff --git a/validation/linear/call-inline.c b/validation/linear/call-inline.c
index d931a3cba..a33f0a1c8 100644
--- a/validation/linear/call-inline.c
+++ b/validation/linear/call-inline.c
@@ -10,7 +10,6 @@ int i3(void) { return (***fun)(); }		// C99,C11 6.5.3.2p4
 /*
  * check-name: inline calls
  * check-command: test-linearize -Wno-decl $file
- * check-known-to-fail
  *
  * check-output-ignore
  * check-output-excludes: load
diff --git a/validation/sizeof-function.c b/validation/sizeof-function.c
index 20c795e94..27d535d4e 100644
--- a/validation/sizeof-function.c
+++ b/validation/sizeof-function.c
@@ -36,7 +36,6 @@ int test(void)
 /*
  * check-name: sizeof-function
  * check-command: sparse -Wno-decl $file
- * check-known-to-fail
  *
  * check-error-start
 sizeof-function.c:22:14: warning: expression using sizeof on a function
-- 
2.15.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-12-21  0:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-12-21  0:19 [PATCH 0/3] multiple dereference in function calls Luc Van Oostenryck
2017-12-21  0:19 ` [PATCH 1/3] add testcases for multiple deref of calls Luc Van Oostenryck
2017-12-21  0:19 ` [PATCH 2/3] avoid unneeded alloc on error path Luc Van Oostenryck
2017-12-21  0:19 ` [PATCH 3/3] dereference of a function is a no-op Luc Van Oostenryck

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).