Bug 29426 - FAIL: gdb.mi/mi-var-invalidate.exp: linteger not anymore in scope due to binary changes (unexpected output)
Summary: FAIL: gdb.mi/mi-var-invalidate.exp: linteger not anymore in scope due to bina...
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: mi (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-07-28 14:33 UTC by Tom de Vries
Modified: 2022-08-12 11:12 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
add_varobj_global_flag.patch (683 bytes, patch)
2022-07-29 15:08 UTC, Lancelot SIX
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tom de Vries 2022-07-28 14:33:19 UTC
I'm running into:
...
FAIL: gdb.mi/mi-var-invalidate.exp: linteger not anymore in scope due to binary changes (unexpected output)
FAIL: gdb.mi/mi-var-invalidate.exp: no type for invalid variable linteger (1) (unexpected output)
...

In more detail:
...
PASS: gdb.mi/mi-var-invalidate.exp: set format variable float_simple
Expecting: ^(-var-update linteger[^M
]+)?(\^done,changelist=\[{name="linteger",in_scope="invalid",has_more="0"}\][^M
]+[(]gdb[)] ^M
[ ]*)
-var-update linteger^M
^done,changelist=[{name="linteger",in_scope="false",type_changed="false",has_more="0"}]^M
(gdb) ^M
FAIL: gdb.mi/mi-var-invalidate.exp: linteger not anymore in scope due to binary changes (unexpected output)
...

Also I'm seeing these, and assuming they're related:
...
FAIL: gdb.mi/mi-var-invalidate-shlib.exp: separate_debuginfo=0: in new process: global_var recreated (unexpected output)
FAIL: gdb.mi/mi-var-invalidate-shlib.exp: separate_debuginfo=1: in new process: global_var recreated (unexpected output)
...
Comment 1 Lancelot SIX 2022-07-29 09:28:58 UTC
I could not see those issues on ubuntu-20.04 (gcc-9.4.0) nor ubuntu-22.04 (gcc-11.2.0).

I finally managed to reproduce it on opensuse/tumbleweed which uses gcc-12.1.1.

Turns out that if I compile the testcase with HEAD gcc (13.0.0) on ubuntu, I can reproduce the issue:

```
$ $HOME/opt/gcc/bin/gcc --version
gcc (GCC) 13.0.0 20220729 (experimental)
Copyright © 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# make check-gdb \
    TESTS="gdb.mi/mi-var-invalidate-shlib.exp gdb.mi/mi-var-invalidate.exp" \
    RUNTESTFLAGS=CC_FOR_TARGET=$HOME/opt/gcc/bin/gcc
[...]
Running /home/lsix/dev/binutils-gdb/_build/gdb/testsuite/../../../gdb/testsuite/gdb.mi/mi-var-invalidate-shlib.exp ...
FAIL: gdb.mi/mi-var-invalidate-shlib.exp: separate_debuginfo=0: in new process: global_var recreated (unexpected output)
FAIL: gdb.mi/mi-var-invalidate-shlib.exp: separate_debuginfo=1: in new process: global_var recreated (unexpected output)
Running /home/lsix/dev/binutils-gdb/_build/gdb/testsuite/../../../gdb/testsuite/gdb.mi/mi-var-invalidate.exp ...
FAIL: gdb.mi/mi-var-invalidate.exp: linteger not anymore in scope due to binary changes (unexpected output)
FAIL: gdb.mi/mi-var-invalidate.exp: no type for invalid variable linteger (1) (unexpected output)

                === gdb Summary ===

# of expected passes            56
# of unexpected failures        4
```

I’ll investigate further to see what changed in the compiler’s output.
Comment 2 Tom de Vries 2022-07-29 10:05:18 UTC
(In reply to Lancelot SIX from comment #1)
> I could not see those issues on ubuntu-20.04 (gcc-9.4.0) nor ubuntu-22.04
> (gcc-11.2.0).
> 
> I finally managed to reproduce it on opensuse/tumbleweed which uses
> gcc-12.1.1.
> 
> Turns out that if I compile the testcase with HEAD gcc (13.0.0) on ubuntu, I
> can reproduce the issue:
> 

FWIW, I'm ran into it on openSUSE Leap 15.3, using gcc 7.5.0.

Also reproduces for me with gcc 8.2.1, 9.3.1, 10.3.0, 11.2.1, and 12.1.1 as well as with clang 8.0.1 and 13.0.0.
Comment 3 Tom de Vries 2022-07-29 10:31:15 UTC
I've bisected the fails in gdb.mi/mi-var-invalidate.exp to commit bc20e562ec0 ("gdb/varobj: Fix use after free in varobj").

Note btw that that commit doesn't touch that test-case:
...
$ git show bc20e562ec0436b6117b989c0e3d8f66c9d4d979 | grep diff
diff --git a/gdb/testsuite/gdb.mi/mi-var-invalidate-shlib-lib.c b/gdb/testsuite/gdb.mi/mi-var-invalidate-shlib-lib.c
diff --git a/gdb/testsuite/gdb.mi/mi-var-invalidate-shlib.c b/gdb/testsuite/gdb.mi/mi-var-invalidate-shlib.c
diff --git a/gdb/testsuite/gdb.mi/mi-var-invalidate-shlib.exp b/gdb/testsuite/gdb.mi/mi-var-invalidate-shlib.exp
diff --git a/gdb/value.c b/gdb/value.c
diff --git a/gdb/varobj.c b/gdb/varobj.c
...
Comment 4 Tom de Vries 2022-07-29 11:05:22 UTC
Hmm, maybe this is the root cause:
...
$ file outputs/gdb.mi/mi-var-invalidate/mi-var-invalidate
outputs/gdb.mi/mi-var-invalidate/mi-var-invalidate: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=78504e3e944b94c9646d9434157eb089b28570ea, for GNU/Linux 3.2.0, with debug_info, not stripped
$ file outputs/gdb.mi/mi-var-invalidate/mi-var-invalidate_bis 
outputs/gdb.mi/mi-var-invalidate/mi-var-invalidate_bis: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=78504e3e944b94c9646d9434157eb089b28570ea, for GNU/Linux 3.2.0, with debug_info, not stripped
...

Identical BuildID between mi-var-invalidate and mi-var-invalidate_bis.
Comment 5 Tom de Vries 2022-07-29 12:28:01 UTC
I observe the following sequence of events:
- varobj_create creates var and sets var.root.valid_block to non-null
- varobj_invalidate_if_uses_objfile
  sets valid_block to null
- varobj_invalidate_iter inspects var.root.valid_block, sees it's null,
  and decided that it's a global variable and tries to recreate it, which
  succeeds.
Comment 6 Lancelot SIX 2022-07-29 13:01:25 UTC
Hi

This is what I also see.  TBH, I am really wondering why I have not seen with my testing and with my ubuntu boxes.

I am working on a fix for this.

Thanks for taking the time and looking into it.
Comment 7 Tom de Vries 2022-07-29 13:46:21 UTC
(In reply to Lancelot SIX from comment #6)
> Hi
> 
> This is what I also see.  TBH, I am really wondering why I have not seen
> with my testing and with my ubuntu boxes.
> 

It's PIE vs. no-PIE (and not for the first time ;) ).

So my system has no-PIE by default (because I haven't installed the gcc-PIE package).

Using target board unix/-fPIE/-pie (case PIE), the test passes.  Using unix (case no-PIE), it fails.

On ubuntu, there's a PIE default for system gcc.  When you build gcc from scratch, it probably had no-PIE default instead.

Anyway, in one case (no-PIE) var_create succeeds, in the other (PIE) not.

So, varobj_create calls get_frame_block, which calls block_for_pc, with a relocated pc.  Then block_for_pc calls block_for_pc_sect, which call blockvector_for_pc_sect, which calls find_pc_sect_compunit_symtab, which calls objf->find_pc_sect_compunit_symtab with objf == mi-var-invalidate_bis.

In the PIE case, this query returns null because we try to find an relocated address in an unrelocated objfile.

In the no-PIE case, this query returns non-null because we try to find an non-relocatable address in an non-relocatable objfile.


In the PIE case

> I am working on a fix for this.
> 
> Thanks for taking the time and looking into it.
Comment 8 Lancelot SIX 2022-07-29 15:08:08 UTC
Created attachment 14242 [details]
add_varobj_global_flag.patch

This regression also shows an interesting problem.

Currently, when we unload an objfile and find a varobj which is linked to a block from this objfile, we clear the valid_block pointer to avoid having a stall pointer.  However by doing this, we loose the ability to distinguish a varobj tracking a global (no valid_block associated) to a varobj tracking a local (some valid_block associated).  Later, when we reload a new program and try to recreate varobj for globals, we have false positive and also try to recreate some locals as well.

The attached patch fixes this, but some differences remain whether I ubuntu’s stock GCC or custom built HEAD GCC.
Comment 9 Tom de Vries 2022-07-29 16:25:07 UTC
(In reply to Lancelot SIX from comment #8)
> Created attachment 14242 [details]
> add_varobj_global_flag.patch
> 
> This regression also shows an interesting problem.
> 
> Currently, when we unload an objfile and find a varobj which is linked to a
> block from this objfile, we clear the valid_block pointer to avoid having a
> stall pointer.  However by doing this, we loose the ability to distinguish a
> varobj tracking a global (no valid_block associated) to a varobj tracking a
> local (some valid_block associated).  Later, when we reload a new program
> and try to recreate varobj for globals, we have false positive and also try
> to recreate some locals as well.
> 
> The attached patch fixes this, but some differences remain whether I
> ubuntu’s stock GCC or custom built HEAD GCC.

Ack, this fixes the gdb.mi/mi-var-invalidate.exp regression for me.

But I still see:
...
$ grep ^FAIL: gdb.sum 
FAIL: gdb.mi/mi-var-invalidate-shlib.exp: separate_debuginfo=0: in new process: global_var recreated (unexpected output)
FAIL: gdb.mi/mi-var-invalidate-shlib.exp: separate_debuginfo=1: in new process: global_var recreated (unexpected output)
...
Comment 10 Lancelot SIX 2022-08-12 11:12:41 UTC
Fixes for this issue have landed in master (various patches up to 906dca17d429f468d49a6cc4753993581c51a899).

I think this can now be closed, but please re-open if problems persist.