Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Keith Seitz <keiths@redhat.com>
To: gdb-patches@sourceware.org
Subject: [RFA] Real C++ operator validation
Date: Fri, 18 Sep 2009 23:05:00 -0000	[thread overview]
Message-ID: <4AB4121C.3060803@redhat.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 2226 bytes --]

Hi,

C++ operators have been sorely neglected in gdb's C++ code, especially 
the parser and decode_line, the two biggest interfaces to the user.

This patch is an attempt to mitigate the later by validating operator 
names. For example, one cannot break/list on a function named 
"operator_1", since gdb assumes that anything starting with "operator" 
is an operator.

Originally, I set out (in CVS HEAD) to fix an annoying bug concerning an 
error message when the user attempted to call decode_line with an 
undefined operator. Turns out the fix for this is a little more complex 
than I was hoping, but since I am trying to get all my branch patches 
accepted/committed here, I thought, "What the heck?" :-)

As a result, this patch from my archer-keiths-expr-cumulative branch has 
several (good) side-effects:

1) It properly ignores spaces in operator names. "break operator ++" is 
now valid. [NOTE: No single quotes!]
2) It adds the ability to list/break on conversion operators, e.g., 
"break foo::operator char*". [NOTE: No single quotes!]
3) (The bug I was attempting to fix) It now outputs "the class foo does 
not have any method named operator int*" instead of "the class foo does 
not have any method named operator ator".
4) It removes the assumption that functions starting with the word 
"operator" are really operators. If they are not, it treats them as 
"normal" functions.

I have regression tested this on x86 linux, and there are no 
regressions. [I thought I would explicitly mention this. I always do 
this anyway.]

Ok?/Comments?/Concerns?

Keith

PS. Shortly I'm planning to submit my "realcpp" tests which offers 
substantially more thorough testing of this and a lot more. Consequently 
I've intentionally kept the testing in this patch restricted to the bug 
I originally set out to fix.

ChangeLog
2009-09-18  Keith Seitz  <keiths@redhat.com>

	* cp-support.h (cp_validate_operator): Declare new function.
	* cp-support.c (cp_validate_operator): New function.
	* linespec.c (decode_compound): For C++ check for a valid operator.

testsuite/ChangeLog

2009-09-18  Keith Seitz  <keiths@redhat.com>

	* gdb.cp/cplusfuncs.exp (do_tests): Add check for proper error message
	with invalid operator.


[-- Attachment #2: cp_validate_operator.patch --]
[-- Type: text/plain, Size: 7563 bytes --]

Index: cp-support.h
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.h,v
retrieving revision 1.29
diff -u -p -r1.29 cp-support.h
--- cp-support.h	7 Jul 2009 17:25:11 -0000	1.29
+++ cp-support.h	18 Sep 2009 22:39:55 -0000
@@ -72,6 +72,8 @@ extern struct symbol **make_symbol_overl
 extern struct type *cp_lookup_rtti_type (const char *name,
 					 struct block *block);
 
+extern int cp_validate_operator (const char *input);
+
 /* Functions/variables from cp-namespace.c.  */
 
 extern int cp_is_anonymous (const char *namespace);
Index: cp-support.c
===================================================================
RCS file: /cvs/src/src/gdb/cp-support.c,v
retrieving revision 1.33
diff -u -p -r1.33 cp-support.c
--- cp-support.c	7 Jul 2009 17:25:11 -0000	1.33
+++ cp-support.c	18 Sep 2009 22:39:56 -0000
@@ -32,6 +32,9 @@
 #include "block.h"
 #include "complaints.h"
 #include "gdbtypes.h"
+#include "exceptions.h"
+#include "expression.h"
+#include "value.h"
 
 #include "safe-ctype.h"
 
@@ -70,6 +73,18 @@ struct cmd_list_element *maint_cplus_cmd
 static void maint_cplus_command (char *arg, int from_tty);
 static void first_component_command (char *arg, int from_tty);
 
+/* Operator validation.
+   NOTE: Multi-byte operators (usually the assignment variety operator)
+   must appear before the single byte version, i.e., "+=" before "+".  */
+static const char *operator_tokens[] =
+  {
+    "++", "+=", "+", "->*", "->", "--", "-=", "-", "*=", "*", "/=", "/",
+    "%=", "%", "!=", "==", "!", "&&", "<<=", "<<", ">>=", ">>",
+    "<=", "<", ">=", ">", "~", "&=", "&", "|=", "||", "|", "^=", "^",
+    "=", "()", "[]", ",", "new", "delete"
+    /* new[] and delete[] require special whitespace handling */
+  };
+
 /* Return 1 if STRING is clearly already in canonical form.  This
    function is conservative; things which it does not recognize are
    assumed to be non-canonical, and the parser will sort them out
@@ -909,6 +924,109 @@ first_component_command (char *arg, int 
 
 extern initialize_file_ftype _initialize_cp_support; /* -Wmissing-prototypes */
 
+#define SKIP_SPACE(P)				\
+  do						\
+  {						\
+    while (*(P) == ' ' || *(P) == '\t')		\
+      ++(P);					\
+  }						\
+  while (0)
+
+/* Returns the length of the operator name or 0 if INPUT does not
+   point to a valid C++ operator.  INPUT should start with "operator".  */
+int
+cp_validate_operator (const char *input)
+{
+  int i;
+  char *copy;
+  const char *p;
+  struct expression *expr;
+  struct value *val;
+  struct gdb_exception except;
+  struct cleanup *old_chain;
+
+  p = input;
+
+  /* Most callers appear to do this already, but since this is not
+     really time-critical code, it is double-checked here.  */
+  if (strncmp (p, "operator", 8) == 0)
+    {
+      int valid = 0;
+      p += 8;
+
+      SKIP_SPACE (p);
+      for (i = 0; i < sizeof (operator_tokens) / sizeof (operator_tokens[0]);
+	   ++i)
+	{
+	  int length = strlen (operator_tokens[i]);
+	  /* By using strncmp here, we MUST have operator_tokens ordered!
+	     See additional notes where operator_tokens is defined above.  */
+	  if (strncmp (p, operator_tokens[i], length) == 0)
+	    {
+	      const char *op = p;
+	      valid = 1;
+	      p += length;
+
+	      if (strncmp (op, "new", 3) == 0
+		  || strncmp (op, "delete", 6) == 0)
+		{
+
+		  /* Special case: new[] and delete[].  We must be careful
+		     to swallow whitespace before/in "[]".  */
+		  SKIP_SPACE (p);
+
+		  if (*p == '[')
+		    {
+		      ++p;
+		      SKIP_SPACE (p);
+		      if (*p == ']')
+			++p;
+		      else
+			valid = 0;
+		    }
+		}
+
+	      if (valid)
+		return (p - input);
+	    }
+	}
+
+      /* Check input for a conversion operator.  */
+
+      /* Skip past base typename */
+      while (*p != '*' && *p != '&' && *p != 0 && *p != ' ')
+	++p;
+      SKIP_SPACE (p);
+
+      /* Add modifiers '*'/'&' */
+      while (*p == '*' || *p == '&')
+	{
+	  ++p;
+	  SKIP_SPACE (p);
+	}
+
+      /* Check for valid type.  [Remember: input starts with 
+	 "operator".]  */
+      copy = savestring (input + 8, p - input - 8);
+      expr = NULL;
+      val = NULL;
+      TRY_CATCH (except, RETURN_MASK_ALL)
+	{
+	  expr = parse_expression (copy);
+	  val = evaluate_type (expr);
+	}
+
+      xfree (copy);
+      if (expr)
+	xfree (expr);
+
+      if (val != NULL && value_type (val) != NULL)
+	return (p - input);
+    }
+
+  return 0;
+}
+
 void
 _initialize_cp_support (void)
 {
Index: linespec.c
===================================================================
RCS file: /cvs/src/src/gdb/linespec.c,v
retrieving revision 1.89
diff -u -p -r1.89 linespec.c
--- linespec.c	14 Aug 2009 00:32:32 -0000	1.89
+++ linespec.c	18 Sep 2009 22:39:56 -0000
@@ -30,6 +30,7 @@
 #include "value.h"
 #include "completer.h"
 #include "cp-abi.h"
+#include "cp-support.h"
 #include "parser-defs.h"
 #include "block.h"
 #include "objc-lang.h"
@@ -1257,6 +1258,9 @@ decode_compound (char **argptr, int funf
       /* Move pointer ahead to next double-colon.  */
       while (*p && (p[0] != ' ') && (p[0] != '\t') && (p[0] != '\''))
 	{
+	  if (current_language->la_language == language_cplus)
+	    p += cp_validate_operator (p);
+
 	  if (p[0] == '<')
 	    {
 	      temp_end = find_template_name_end (p);
@@ -1334,6 +1338,15 @@ decode_compound (char **argptr, int funf
 	  while (*p && *p != ' ' && *p != '\t' && *p != ',' && *p != ':')
 	    p++;
 	  /* At this point p->"".  String ended.  */
+	  /* Nope, C++ operators could have spaces in them
+	     ("foo::operator <" or "foo::operator delete []").
+	     I apologize, this is a bit hacky...  */
+	  if (current_language->la_language == language_cplus
+	      && *p == ' ' && p - 8 - *argptr + 1 > 0)
+	    {
+	      /* The above loop has already swallowed "operator".  */
+	      p += cp_validate_operator (p - 8) - 8;
+	    }
 	}
 
       /* Allocate our own copy of the substring between argptr and
@@ -1474,26 +1487,16 @@ find_method (int funfirstline, char ***c
     }
   else
     {
-      char *tmp;
-
-      if (is_operator_name (copy))
-	{
-	  tmp = (char *) alloca (strlen (copy + 3) + 9);
-	  strcpy (tmp, "operator ");
-	  strcat (tmp, copy + 3);
-	}
-      else
-	tmp = copy;
       if (not_found_ptr)
         *not_found_ptr = 1;
-      if (tmp[0] == '~')
+      if (copy[0] == '~')
 	cplusplus_error (saved_arg,
 			 "the class `%s' does not have destructor defined\n",
 			 SYMBOL_PRINT_NAME (sym_class));
       else
 	cplusplus_error (saved_arg,
 			 "the class %s does not have any method named %s\n",
-			 SYMBOL_PRINT_NAME (sym_class), tmp);
+			 SYMBOL_PRINT_NAME (sym_class), copy);
     }
 }
 
Index: testsuite/gdb.cp/cplusfuncs.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.cp/cplusfuncs.exp,v
retrieving revision 1.7
diff -u -p -r1.7 cplusfuncs.exp
--- testsuite/gdb.cp/cplusfuncs.exp	3 Jan 2009 05:58:04 -0000	1.7
+++ testsuite/gdb.cp/cplusfuncs.exp	18 Sep 2009 22:39:56 -0000
@@ -534,6 +534,7 @@ proc do_tests {} {
     global srcdir
     global binfile
     global gdb_prompt
+    global dm_type_int_star
 
     set prms_id 0
     set bug_id 0
@@ -557,6 +558,10 @@ proc do_tests {} {
     test_paddr_operator_functions
     test_paddr_hairy_functions
     test_lookup_operator_functions
+
+    # A regression test on errors involving operators
+    gdb_test "list foo::operator $dm_type_int_star" \
+	".*the class foo does not have any method named operator $dm_type_int_star.*"
 }
 
 do_tests

             reply	other threads:[~2009-09-18 23:05 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-09-18 23:05 Keith Seitz [this message]
2009-09-20 20:34 ` Daniel Jacobowitz
2009-09-21 19:47   ` Keith Seitz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4AB4121C.3060803@redhat.com \
    --to=keiths@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox