Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Andrew Burgess <andrew.burgess@embecosm.com>
To: Tom de Vries <tdevries@suse.de>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH 3/3][gdb/testsuite] Warn about leaked global array
Date: Tue, 2 Jun 2020 21:18:29 +0100	[thread overview]
Message-ID: <20200602201829.GC3522@embecosm.com> (raw)
In-Reply-To: <20200602170139.GB3522@embecosm.com>

* Andrew Burgess <andrew.burgess@embecosm.com> [2020-06-02 18:01:39 +0100]:

> * Tom de Vries <tdevries@suse.de> [2020-06-02 18:31:39 +0200]:
> 
> > On 02-06-2020 17:52, Andrew Burgess wrote:
> > > * Andrew Burgess <andrew.burgess@embecosm.com> [2020-06-02 16:38:30 +0100]:
> > > 
> > >> * Tom de Vries <tdevries@suse.de> [2020-05-19 18:30:06 +0200]:
> > >>
> > >>> Hi,
> > >>>
> > >>> A variable name cannot be used both as scalar and array without an
> > >>> intermediate unset.  Trying to do so will result in tcl errors, for
> > >>> example, for:
> > >>> ...
> > >>>   set var "bla"
> > >>>   set var(1) "bla"
> > >>> ...
> > >>> we get:
> > >>> ...
> > >>>   can't set "var(1)": variable isn't array
> > >>> ...
> > >>> and for the reverse statement order we get:
> > >>> ...
> > >>>   can't set "var": variable is array
> > >>> ...
> > >>>
> > >>> So, since a global name in one test-case can leak to another
> > >>> test-case, setting a global name in one test-case can result in
> > >>> a tcl error in another test-case that reuses the name in a different
> > >>> way.
> > >>>
> > >>> Warn about leaking a global array from a test-case.
> > >>>
> > >>> Also, add a possibility to skip the warning in a given test-case using
> > >>> variable gdb_skip_check_global_vars, and use it in gdb.mi/mi2-var-child.exp
> > >>> and gdb.mi/mi-var-cp.exp.
> > >>>
> > >>> Tested on x86_64-linux.
> > >>>
> > >>> Any comments?
> > >>
> > >> If we're going to add code to loop over all globals anyway, then why
> > >> not, instead of warning about bad cases, and then wrapping tests in a
> > >> namespace, just have this code "fix" the leaked globals by deleting
> > >> them?
> > >>
> > >> My thinking is that any global that exists when we start a test should
> > >> continue to exist at the end of the test.  Any other global should
> > >> just be unset when the test script finishes.
> > >>
> > >> If there really is some global state that is lazily created by a
> > >> particular test script then (a) this seems like a bug anyway, and (b)
> > >> this is easy to fix by giving it an earlier creation / initialisation.
> > >>
> > >> In this way, folk can just write test scripts, dump their junk all
> > >> over the global namespace as they like, and we'll just clean up for
> > >> them.
> > >>
> > >> Thoughts?
> > > 
> > > Here's a really quick patch implementing the idea above.  It needs
> > > cleaning up and commenting, etc, but it passes the testsuite with no
> > > regressions, and taking a look at its debug output, I can see it
> > > deleting some of the problem global arrays that are causing issues.
> > > 
> > > What do you think of this approach?
> > > 
> > > Thanks,
> > > Andrew
> > > 
> > > ----
> > > 
> > > diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> > > index 444cea01c36..c983c9cc172 100644
> > > --- a/gdb/testsuite/lib/gdb.exp
> > > +++ b/gdb/testsuite/lib/gdb.exp
> > > @@ -5094,7 +5094,11 @@ set banned_procedures { strace }
> > >  # if the banned variables and procedures are already traced.
> > >  set banned_traced 0
> > >  
> > > +array set known_globals {}
> > > +
> > >  proc gdb_init { test_file_name } {
> > > +    global known_globals
> > > +
> > >      # Reset the timeout value to the default.  This way, any testcase
> > >      # that changes the timeout value without resetting it cannot affect
> > >      # the timeout used in subsequent testcases.
> > > @@ -5196,13 +5200,27 @@ proc gdb_init { test_file_name } {
> > >      global gdb_instances
> > >      set gdb_instances 0
> > >  
> > > -    return [default_gdb_init $test_file_name]
> > > +    set result [default_gdb_init $test_file_name]
> > > +
> > > +    foreach varname [info globals] {
> > > +	set known_globals($varname) 1
> > > +    }
> > > +
> > > +    return $result
> > >  }
> > >  
> > >  proc gdb_finish { } {
> > >      global gdbserver_reconnect_p
> > >      global gdb_prompt
> > >      global cleanfiles
> > > +    global known_globals
> > > +
> > > +    foreach varname [info globals] {
> > > +	if {![info exists known_globals($varname)]} {
> > > +	    verbose -log "APB: Deleting '$varname'"
> > > +	    upvar 0 unset $varname
> > > +	}
> > > +    }
> > 
> > I'm not against the approach as such (I remember also trying this out
> > initially).
> > 
> > I don't think this use of upvar does any unset though.
> 
> *cough* yeah, I knew that.
> 
> Fixed, and _confirmed_ that it's deleting the globals this time, not
> just reporting what it would delete.

Here's a cleaned up version for consideration.

Thanks,
Andrew

---

commit f21ca01deceab0fbbfc22e960c1ee5178cb4a496
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Tue Jun 2 21:11:10 2020 +0100

    gdb/testsuite: Prevent globals leaking between test scripts
    
    Many of the test scripts create variables in the global namespace,
    these variables will then be present for the following test scripts.
    In most cases this is harmless, but in some cases this can cause
    problems.
    
    For example, if a variable is created as an array in one script, but
    then assigned as a scalar in a different script, this will cause a TCL
    error.
    
    The solution proposed in this patch is to have the GDB test harness
    record a list of all known global variables at the point just before
    we source the test script.  Then, after the test script has run, we
    again iterate over all global variables.  Any variable that was not in
    the original list is deleted.
    
    The assumption here is that no test script should need to create a
    global variable that will outlive the lifetime of the test script
    itself.  With this patch in place all tests currently seem to pass, so
    the assumption seems to hold.
    
    gdb/testsuite/ChangeLog:
    
            * lib/gdb.exp (gdb_known_globals): New global.
            (gdb_setup_known_globals): New proc.
            (gdb_cleanup_globals): New proc.

diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 444cea01c36..66de9d6be3f 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -5094,6 +5094,35 @@ set banned_procedures { strace }
 # if the banned variables and procedures are already traced.
 set banned_traced 0
 
+# Global array that holds the name of all global variables at the time
+# a test script is started.  After the test script has completed any
+# global not in this list is deleted.
+array set gdb_known_globals {}
+
+# Setup the GDB_KNOWN_GLOBALS array with the names of all current
+# global variables.
+proc gdb_setup_known_globals {} {
+    global gdb_known_globals
+
+    array set gdb_known_globals {}
+    foreach varname [info globals] {
+	set gdb_known_globals($varname) 1
+    }
+}
+
+# Cleanup the global namespace.  Any global not in the
+# GDB_KNOWN_GLOBALS array is unset, this ensures we don't "leak"
+# globals from one test script to another.
+proc gdb_cleanup_globals {} {
+    global gdb_known_globals
+
+    foreach varname [info globals] {
+	if {![info exists gdb_known_globals($varname)]} {
+	    uplevel #0 unset $varname
+	}
+    }
+}
+
 proc gdb_init { test_file_name } {
     # Reset the timeout value to the default.  This way, any testcase
     # that changes the timeout value without resetting it cannot affect
@@ -5196,13 +5225,16 @@ proc gdb_init { test_file_name } {
     global gdb_instances
     set gdb_instances 0
 
-    return [default_gdb_init $test_file_name]
+    set result [default_gdb_init $test_file_name]
+    gdb_setup_known_globals
+    return $result
 }
 
 proc gdb_finish { } {
     global gdbserver_reconnect_p
     global gdb_prompt
     global cleanfiles
+    global known_globals
 
     # Exit first, so that the files are no longer in use.
     gdb_exit
@@ -5228,6 +5260,8 @@ proc gdb_finish { } {
 	}
 	set banned_traced 0
     }
+
+    gdb_cleanup_globals
 }
 
 global debug_format


  reply	other threads:[~2020-06-02 20:18 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-19 16:30 Tom de Vries
2020-05-22 20:15 ` Tom Tromey
2020-06-02 13:08   ` Tom de Vries
2020-06-02 15:38 ` Andrew Burgess
2020-06-02 15:52   ` Andrew Burgess
2020-06-02 16:31     ` Tom de Vries
2020-06-02 17:01       ` Andrew Burgess
2020-06-02 20:18         ` Andrew Burgess [this message]
2020-06-03  8:47           ` Tom de Vries
2020-06-03  9:38             ` Tom de Vries
2020-06-03 10:09               ` Tom de Vries
2020-06-03 10:24                 ` Tom de Vries
2020-06-03 12:54                   ` Andrew Burgess
2020-06-03 15:35                     ` Tom de Vries
2020-06-04 11:16                       ` Pedro Alves
2020-06-04 12:29                         ` Tom de Vries
2020-06-12 13:11                           ` [committed] gdb/testsuite: Prevent globals leaking between test scripts Tom de Vries
2020-06-03  9:49   ` [PATCH 3/3][gdb/testsuite] Warn about leaked global array Pedro Alves
2020-06-04 11:40     ` Tom de Vries
2020-06-05 10:06       ` [PATCH][gdb/testsuite] Don't leak tuiterm.exp spawn override Tom de Vries
2020-06-11 13:55         ` Tom Tromey
2020-06-12 11:36           ` [committed][gdb/testsuite] " Tom de Vries
2020-06-15 19:46             ` Tom Tromey
2020-06-17 14:55               ` Tom de Vries
2020-06-17 15:28                 ` Andreas Schwab
2020-06-11 12:11       ` [committed][gdb/testsuite] Make gdb.base/dbx.exp more robust Tom de Vries
2020-06-11 12:16         ` Pedro Alves
2020-06-11 14:39         ` Simon Marchi
2020-06-11 14:52           ` Tom de Vries
2020-06-11 14:59             ` Simon Marchi

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=20200602201829.GC3522@embecosm.com \
    --to=andrew.burgess@embecosm.com \
    --cc=gdb-patches@sourceware.org \
    --cc=tdevries@suse.de \
    /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