[gdb/testsuite] Work around tcl bug in libsegfault.exp with check-read1
authorTom de Vries <tdevries@suse.de>
Tue, 30 Jul 2019 14:15:46 +0000 (16:15 +0200)
committerTom de Vries <tdevries@suse.de>
Tue, 30 Jul 2019 14:15:46 +0000 (16:15 +0200)
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.

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/ChangeLog
gdb/testsuite/lib/read1.c

index 3476d7f..0bf6be9 100644 (file)
@@ -1,5 +1,10 @@
 2019-07-30  Tom de Vries  <tdevries@suse.de>
 
+       * lib/read1.c (read): Don't use unsetenv (v), use setenv (v, "", 1)
+       instead.
+
+2019-07-30  Tom de Vries  <tdevries@suse.de>
+
        PR testsuite/24834
        * lib/gdb.exp (gdb_compile): Fail if nopie results in PIE executable.
        (exec_is_pie): New proc.
index 0547661..bee0945 100644 (file)
@@ -31,7 +31,11 @@ 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");
+      /* Use setenv (v, "", 1) rather than unsetenv (v) to work around
+         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".  */
+      setenv ("LD_PRELOAD", "", 1);
       read2 = dlsym (RTLD_NEXT, "read");
     }
   if (count > 1 && isatty (fd) >= 1)