llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.03k stars 11.58k forks source link

[libc++] Vector index starts at 1 instead of 0 in pretty-printing with libc++ in gdb #62168

Open hiratasa opened 1 year ago

hiratasa commented 1 year ago

When debugging a program using libc++ by gdb with the pretty-printer script provided by https://github.com/llvm/llvm-project/blob/main/libcxx/utils/gdb/libcxx/printers.py, the output of the pretty-printing for the vector's index starts from 1 instead of 0.

GDB does not display the index of a std::vector in normal mode, but it can be shown in MI mode and therefore also appears in some IDEs, such as VSCode. (ADDED: I append steps to reproduce using GDB's MI mode directly)

For the following vector,

  std::vector<int> v{0, 1, 2, 3, 4, 5, 6};

GDB in normal mode outputs the following, with the index omitted:

$1 = std::vector of length 7, capacity 7 = {0, 1, 2, 3, 4, 5, 6}

And in VSCode, the view shows the following, with the index starting at 1:

image

(Note that if I use libstdc++ instead of libc++, the index starts at 0)

It appears that the code in https://github.com/llvm/llvm-project/blob/main/libcxx/utils/gdb/libcxx/printers.py#L375-L381 is responsible for this behavior.

        def __next__(self):
            self.count += 1
            if self.item == self.end:
                raise StopIteration
            entry = self.item.dereference()
            self.item += 1
            return ("[%d]" % self.count, entry)

This code returns 1 as index for the first element.

UPDATE: I confirmed that by changing the return statement as follows, the expected behavior can be obtained in GDB's MI mode and in VSCode:

            return ("[%d]" % (self.count - 1), entry)

UPDATE END

I'm not sure whether this is intended behavior or a bug, but it would be helpful if this issue could be addressed. Thank you.


ADDED: Following are steps to reproduce using GDB's MI mode directly

  1. Create a.cpp as shown below and build it with debug information and link to libc++:
    
    #include <vector>

int main() { std::vector v{0, 1, 2};

return 0;

}


2. Run the following commands in the terminal (the second and subsequent lines are inputs to gdb):
```sh
$ gdb --interpreter=mi ./a.out
-enable-pretty-printing
b a.cpp:9
r
-var-create v * v
-var-list-children v

Result

The following result is obtained:

^done,numchild="3",displayhint="array",children=[child={name="v.[1]",exp="[1]",numchild="0",type="int",thread-id="1"},child={name="v.[2]",exp="[2]",numchild="0",type="int",thread-id="1"},child={name="v.[3]",exp="[3]",numchild="0",type="int",thread-id="1"}],has_more="0"

The name and exp of the first child is [1].

For reference, the following is the result of a similar experiment with libstdc++:

^done,numchild="3",displayhint="array",children=[child={name="v.[0]",exp="[0]",numchild="0",type="int",thread-id="1"},child={name="v.[1]",exp="[1]",numchild="0",type="int",thread-id="1"},child={name="v.[2]",exp="[2]",numchild="0",type="int",thread-id="1"}],has_more="0"
shafik commented 1 year ago

I think this would be a libc++ issue but not 100% sure CC @mordante @ldionne

hiratasa commented 1 year ago

I found that tuple's index also starts at 1, and this is not omitted in GDB in CLI:

#include <iostream>
#include <tuple>

int main() {
    std::tuple<int, int, int> t{0, 1, 2};

    return 0;
}
(gdb) p t
$1 = std::tuple containing = {[1] = 0, [2] = 1, [3] = 2}
hiratasa commented 1 year ago

@shafik Thank you for the reply!


I edited the issue for the following information: