[PATCH 2/3 trunk+branch] libctf: lookup_by_name: do not return success for nonexistent pointer types

Nick Alcock nick.alcock@oracle.com
Mon Jan 18 12:53:50 GMT 2021


The recent work allowing lookups of pointers in child dicts when the
pointed-to type is in the parent dict broke the case where a pointer
type that does not exist at all is looked up: we mistakenly return the
pointed-to type, which is likely not a pointer at all.  This causes
considerable confusion.

Fixed, with a new testcase.

libctf/ChangeLog
2021-01-12  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-lookup.c (ctf_lookup_by_name_internal): Do not return the
	base type if looking up a nonexistent pointer type.
	* testsuite/libctf-regression/pptrtab*: Test it.
---
 libctf/ctf-lookup.c                           | 34 ++++++++++++++-----
 .../testsuite/libctf-regression/pptrtab-a.c   |  2 ++
 .../testsuite/libctf-regression/pptrtab-b.c   |  3 +-
 libctf/testsuite/libctf-regression/pptrtab.c  | 10 +++++-
 4 files changed, 39 insertions(+), 10 deletions(-)

This breaks a widely-used function (probably the most widely-used querying
function in libctf given the absence of ctf_lookup_by_symbol until now)
with impacts on real software, was broken during this cycle, and is lookup
API only so cannot break the rest of binutils (it is not used by any
machinery called directly or indirectly by ld), so I'd hope it's OK on
the branch.

diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index c7f7e297822..6d4e085838c 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -184,24 +184,36 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
 	     from resolving the type down to its base type and use that instead.
 	     This helps with cases where the CTF data includes "struct foo *"
 	     but not "foo_t *" and the user tries to access "foo_t *" in the
-	     debugger.  */
+	     debugger.
+
+	     There is extra complexity here because uninitialized elements in
+	     the pptrtab and ptrtab are set to zero, but zero (as the type ID
+	     meaning the unimplemented type) is a valid return type from
+	     ctf_lookup_by_name.  (Pointers to types are never of type 0, so
+	     this is unambiguous, just fiddly to deal with.)  */
 
 	  uint32_t idx = LCTF_TYPE_TO_INDEX (fp, type);
 	  int in_child = 0;
 
-	  ntype = type;
+	  ntype = CTF_ERR;
 	  if (child && idx <= child->ctf_pptrtab_len)
 	    {
 	      ntype = child->ctf_pptrtab[idx];
 	      if (ntype)
 		in_child = 1;
+	      else
+		ntype = CTF_ERR;
 	    }
 
-	  if (ntype == 0)
-	    ntype = fp->ctf_ptrtab[idx];
+	  if (ntype == CTF_ERR)
+	    {
+	      ntype = fp->ctf_ptrtab[idx];
+	      if (ntype == 0)
+		ntype = CTF_ERR;
+	    }
 
 	  /* Try resolving to its base type and check again.  */
-	  if (ntype == 0)
+	  if (ntype == CTF_ERR)
 	    {
 	      if (child)
 		ntype = ctf_type_resolve_unsliced (child, type);
@@ -213,16 +225,22 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
 
 	      idx = LCTF_TYPE_TO_INDEX (fp, ntype);
 
-	      ntype = 0;
+	      ntype = CTF_ERR;
 	      if (child && idx <= child->ctf_pptrtab_len)
 		{
 		  ntype = child->ctf_pptrtab[idx];
 		  if (ntype)
 		    in_child = 1;
+		  else
+		    ntype = CTF_ERR;
 		}
 
-	      if (ntype == 0)
-		ntype = fp->ctf_ptrtab[idx];
+	      if (ntype == CTF_ERR)
+		{
+		  ntype = fp->ctf_ptrtab[idx];
+		  if (ntype == 0)
+		    ntype = CTF_ERR;
+		}
 	      if (ntype == CTF_ERR)
 		goto notype;
 	    }
diff --git a/libctf/testsuite/libctf-regression/pptrtab-a.c b/libctf/testsuite/libctf-regression/pptrtab-a.c
index e9f656a0bc8..65414877114 100644
--- a/libctf/testsuite/libctf-regression/pptrtab-a.c
+++ b/libctf/testsuite/libctf-regression/pptrtab-a.c
@@ -1,3 +1,5 @@
 typedef long a_t;
+typedef long b_t;
 
 a_t *a;
+b_t ignore2;
diff --git a/libctf/testsuite/libctf-regression/pptrtab-b.c b/libctf/testsuite/libctf-regression/pptrtab-b.c
index 6142f194c19..e458021efb1 100644
--- a/libctf/testsuite/libctf-regression/pptrtab-b.c
+++ b/libctf/testsuite/libctf-regression/pptrtab-b.c
@@ -1,4 +1,5 @@
 typedef long a_t;
+typedef long b_t;
 
 a_t b;
-
+b_t ignore1;
diff --git a/libctf/testsuite/libctf-regression/pptrtab.c b/libctf/testsuite/libctf-regression/pptrtab.c
index 5d3c2f2ee93..fe1b8fe2b43 100644
--- a/libctf/testsuite/libctf-regression/pptrtab.c
+++ b/libctf/testsuite/libctf-regression/pptrtab.c
@@ -23,13 +23,18 @@ main (int argc, char *argv[])
     goto open_err;
 
   /* Make sure we can look up a_t * by name in all non-parent dicts, even though
-     the a_t * and the type it points to are in distinct dicts.  */
+     the a_t * and the type it points to are in distinct dicts; make sure we
+     cannot look up b_t *.  */
 
   while ((fp = ctf_archive_next (ctf, &i, &arcname, 1, &err)) != NULL)
     {
       if ((type = ctf_lookup_by_name (fp, "a_t *")) == CTF_ERR)
 	goto err;
 
+      if ((ctf_lookup_by_name (fp, "b_t *")) != CTF_ERR ||
+          ctf_errno (fp) != ECTF_NOTYPE)
+	goto noerr;
+
       if (ctf_type_reference (fp, type) == CTF_ERR)
 	goto err;
 
@@ -51,4 +56,7 @@ main (int argc, char *argv[])
  err:
   fprintf (stderr, "Lookup failed in %s: %s\n", arcname, ctf_errmsg (ctf_errno (fp)));
   return 1;
+ noerr:
+  fprintf (stderr, "Lookup unexpectedly succeeded in %s\n", arcname);
+  return 1;
 }
-- 
2.30.0.252.gc27e85e57d



More information about the Binutils mailing list