[gdb/testsuite] Work around tcl bug in libsegfault.exp with check-read1

Message ID 20190730132443.GA16765@delia
State New, archived
Headers

Commit Message

Tom de Vries July 30, 2019, 1:24 p.m. UTC
  Hi,

When running libsegfault.exp with check-read1, I get:
...
Running gdb/testsuite/gdb.base/libsegfault.exp ...
ERROR: tcl error sourcing gdb/testsuite/gdb.base/libsegfault.exp.
ERROR: no such variable
    (read trace on "env(LD_PRELOAD)")
    invoked from within
"set env(LD_PRELOAD)"
    ("uplevel" body line 1)
    invoked from within
"uplevel 1 [list set $var]"
    invoked from within
"if [uplevel 1 [list array exists $var]] {
                set saved_arrays($var) [uplevel 1 [list array get $var]]
            } else {
                set saved_scalars($var) [uplevel ..."
    invoked from within
"if [uplevel 1 [list info exists $var]] {
            if [uplevel 1 [list array exists $var]] {
                set saved_arrays($var) [uplevel 1 [list array get $var]]
          ..."
    (procedure "save_vars" line 11)
    invoked from within
"save_vars { env(LD_PRELOAD) } {
        if { ![info exists env(LD_PRELOAD) ]
             || $env(LD_PRELOAD) == "" } {
            set env(LD_PRELOAD) "$lib"
        } else {
         ..."
    (procedure "gdb_spawn_with_ld_preload" line 4)
    invoked from within
"gdb_spawn_with_ld_preload $libsegfault """
...

There are several things here interacting with environment variable
LD_PRELOAD:
- the expect "binary" build/gdb/testsuite/expect-read1 with does
  export LD_PRELOAD=build/gdb/testsuite/read1.so before calling native expect
- read1.so which does unsetenv ("LD_PRELOAD") upon first call to read
- the test-case, which wants to set or append libSegFault.so to LD_PRELOAD

The error occurs when accessing $env(LD_PRELOAD), in a branch where
"info exists env(LD_PRELOAD)" returns true. AFAIU, this is
https://core.tcl-lang.org/tcl/tktview?name=67fd4f973a "incorrect results of
'info exists' when unset env var in one interp and check for existence from
another interp".

Work around the tcl bug by not unsetting the variable, but setting it to ""
instead:
...
-      unsetenv ("LD_PRELOAD");
+      setenv ("LD_PRELOAD", "", 1);
...

Verified that reverting commit de28a3b72e "[gdb/testsuite, 2/2] Fix
gdb.linespec/explicit.exp with check-read1" reintroduced the check-read1
failure in gdb.linespec/explicit.exp.

This fixes a similar error in attach-slow-waitpid.exp, which also sets
LD_PRELOAD.

Tested on x86_64-linux with check-read1.

OK for trunk?

Thanks,
- Tom

[gdb/testsuite] Work around tcl bug in libsegfault.exp with check-read1

gdb/testsuite/ChangeLog:

2019-07-30  Tom de Vries  <tdevries@suse.de>

	* lib/read1.c (read): Don't use unsetenv (v), use setenv (v, "", 1)
	instead.

---
 gdb/testsuite/lib/read1.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
  

Comments

Tom Tromey July 30, 2019, 2:06 p.m. UTC | #1
>>>>> "Tom" == Tom de Vries <tdevries@suse.de> writes:

Tom> The error occurs when accessing $env(LD_PRELOAD), in a branch where
Tom> "info exists env(LD_PRELOAD)" returns true. AFAIU, this is
Tom> https://core.tcl-lang.org/tcl/tktview?name=67fd4f973a "incorrect results of
Tom> 'info exists' when unset env var in one interp and check for existence from
Tom> another interp".

Nice diagnosis.

Tom>    if (read2 == NULL)
Tom>      {
Tom> -      unsetenv ("LD_PRELOAD");
Tom> +      setenv ("LD_PRELOAD", "", 1);

I think it would be good to mention some relevant part of the analysis
in a comment here.

Ok with that change.

Tom
  

Patch

diff --git a/gdb/testsuite/lib/read1.c b/gdb/testsuite/lib/read1.c
index 0547661346..485ea682fc 100644
--- a/gdb/testsuite/lib/read1.c
+++ b/gdb/testsuite/lib/read1.c
@@ -31,7 +31,7 @@  read (int fd, void *buf, size_t count)
   static ssize_t (*read2) (int fd, void *buf, size_t count) = NULL;
   if (read2 == NULL)
     {
-      unsetenv ("LD_PRELOAD");
+      setenv ("LD_PRELOAD", "", 1);
       read2 = dlsym (RTLD_NEXT, "read");
     }
   if (count > 1 && isatty (fd) >= 1)