microsoft / microsoft/vscode-cpptools

GDB hangs on breakpoint, infinitely traversing pretty printers

Offen
#14,487 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

debugger help wanted
Vorherrschende Sprache
TypeScript
Sterne
6.2k
Forks
1.7k
Ø Merge
14 Std. 46 Min.
Gemergte PRs (30 T.)
61

Beschreibung

Environment
  • OS and version: Linux Mint 22.3 (inside Distrobox)
  • VS Code: 1.114.0 (e7fb5e96c0730b9deb70b33781f98e2f35975036)
  • C/C++ extension: 1.32.2
  • GDB version: 15.1
Bug Summary and Steps to Reproduce

Bug Summary:
As far as I understand, IDE + GDB should not call "children" method of a pretty-printer unless the user has asked to expand the value in GUI. Moreover, calling "children" method recursively is unacceptable, because linked data structures can be expanded infinitely.
And this is exactly what I see happening in this case: GDB recursively traverses the data structure and hangs because it has loops.

Steps to reproduce:

  1. Clone this repository: https://github.com/stgatilov/vscode-gdb-pretty-printers-hangs-repro-code
  2. Open it in VS Code.
  3. Build Debug build.
  4. Put breakpoint at the only line of badfunc.
  5. Run debugging using the included configuration "Launch with pretty printers".
  6. When debugger stops at the breakpoint, GDB hangs trying to evaluate local variable entity.
Debugger Configurations
{
            "name": "(gdb) Launch with pretty printers",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/build/proj",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                },
                {
                    "description": "Initialize pretty printer",
                    "text": "source ${workspaceFolder}/printers.py"
                }
            ],
            "logging": {
                "engineLogging": true,
                "trace": true,
                "traceResponse": true
            }            
        },
Debugger Logs
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (301) ->~\"Breakpoint 2, badfunc (entity=55555556d2b0 GameEntity(0): \\\"my_entity_0\\\" = {...}) at /home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp:21\\n\"\n"},"seq":421}
1: (301) ->~"Breakpoint 2, badfunc (entity=55555556d2b0 GameEntity(0): \"my_entity_0\" = {...}) at /home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp:21\n"
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (301) ->~\"21\\t    entity->renderParams.color[2] += 1e-3f;\\n\"\n"},"seq":423}
1: (301) ->~"21\t    entity->renderParams.color[2] += 1e-3f;\n"
--> E (output): {"type":"event","event":"output","body":{"category":"stdout","output":"Breakpoint 2, badfunc (entity=55555556d2b0 GameEntity(0): \"my_entity_0\" = {...}) at /home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp:21\n"},"seq":425}
Breakpoint 2, badfunc (entity=55555556d2b0 GameEntity(0): "my_entity_0" = {...}) at /home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp:21
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (301) ->*stopped,reason=\"breakpoint-hit\",disp=\"keep\",bkptno=\"2\",frame={addr=\"0x0000555555555195\",func=\"badfunc\",args=[{name=\"entity\",value=\"55555556d2b0 GameEntity(0): \\\"my_entity_0\\\" = {...}\"}],file=\"/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp\",fullname=\"/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp\",line=\"21\",arch=\"i386:x86-64\"},thread-id=\"1\",stopped-threads=\"all\",core=\"10\"\n"},"seq":426}
1: (301) ->*stopped,reason="breakpoint-hit",disp="keep",bkptno="2",frame={addr="0x0000555555555195",func="badfunc",args=[{name="entity",value="55555556d2b0 GameEntity(0): \"my_entity_0\" = {...}"}],file="/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp",fullname="/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp",line="21",arch="i386:x86-64"},thread-id="1",stopped-threads="all",core="10"
--> E (output): {"type":"event","event":"output","body":{"category":"stdout","output":"21\t    entity->renderParams.color[2] += 1e-3f;\n"},"seq":429}
21	    entity->renderParams.color[2] += 1e-3f;
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (302) <-1025-stack-list-frames 0 1000\n"},"seq":431}
1: (302) <-1025-stack-list-frames 0 1000
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (302) ->1025^done,stack=[frame={level=\"0\",addr=\"0x0000555555555195\",func=\"badfunc\",file=\"/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp\",fullname=\"/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp\",line=\"21\",arch=\"i386:x86-64\"},frame={level=\"1\",addr=\"0x00005555555553d0\",func=\"main\",file=\"/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp\",fullname=\"/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp\",line=\"44\",arch=\"i386:x86-64\"}]\n"},"seq":433}
1: (302) ->1025^done,stack=[frame={level="0",addr="0x0000555555555195",func="badfunc",file="/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp",fullname="/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp",line="21",arch="i386:x86-64"},frame={level="1",addr="0x00005555555553d0",func="main",file="/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp",fullname="/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp",line="44",arch="i386:x86-64"}]
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (302) ->(gdb)\n"},"seq":435}
1: (302) ->(gdb)
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (302) 1025: elapsed time 0\n"},"seq":437}
1: (302) 1025: elapsed time 0
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (303) Send Event AD7BreakpointEvent\n"},"seq":439}
1: (303) Send Event AD7BreakpointEvent
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"Execute debugger commands using \"-exec <command>\", for example \"-exec info registers\" will list registers in use (when GDB is the debugger)\n"},"seq":441}
Execute debugger commands using "-exec <command>", for example "-exec info registers" will list registers in use (when GDB is the debugger)
--> E (stopped): {"type":"event","event":"stopped","body":{"reason":"breakpoint","threadId":2015535,"allThreadsStopped":true,"source":{"name":"main.cpp","path":"/home/stgatilov/cppdev/gdb_pp_hang_repro/main.cpp","sources":[],"checksums":[]},"line":21,"column":1},"seq":443}
<--   C (threads-12): {"command":"threads","type":"request","seq":12}
--> R (threads-12): {"type":"response","request_seq":12,"success":true,"command":"threads","body":{"threads":[{"id":2015535,"name":"proj [2015535]"}]},"seq":446}
<--   C (stackTrace-13): {"command":"stackTrace","arguments":{"threadId":2015535,"startFrame":0,"levels":20},"type":"request","seq":13}
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (323) <-1026-list-features\n"},"seq":449}
1: (323) <-1026-list-features
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (324) ->1026^done,features=[\"frozen-varobjs\",\"pending-breakpoints\",\"thread-info\",\"data-read-memory-bytes\",\"breakpoint-notifications\",\"ada-task-info\",\"language-option\",\"info-gdb-mi-command\",\"undefined-command-error-code\",\"exec-run-start-option\",\"data-disassemble-a-option\",\"simple-values-ref-types\",\"python\"]\n"},"seq":451}
1: (324) ->1026^done,features=["frozen-varobjs","pending-breakpoints","thread-info","data-read-memory-bytes","breakpoint-notifications","ada-task-info","language-option","info-gdb-mi-command","undefined-command-error-code","exec-run-start-option","data-disassemble-a-option","simple-values-ref-types","python"]
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (324) ->(gdb)\n"},"seq":453}
1: (324) ->(gdb)
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (325) 1026: elapsed time 1\n"},"seq":455}
1: (325) 1026: elapsed time 1
--> E (output): {"type":"event","event":"output","body":{"category":"console","output":"1: (326) <-1027-stack-list-arguments 2 0 1\n"},"seq":457}
1: (326) <-1027-stack-list-arguments 2 0 1
Other Extensions

No response

Additional Information

You can uncomment print statements in printers.py and confirm that children methods of pretty printers are called endlessly while GDB hangs. The last command that is sent to GDB is -stack-list-arguments 2 0 1, and GDB never responds to it.

According to GDB-MI docs, print-values = 2 or --simple-values means: "print the name, type and value for simple data types, and the name and type for arrays, structures and unions."
I suspect that pointers are also considered "simple data types", even when they are covered by pretty printers and have children. So GDB tries to return the value of a pointer by deep-printing it. Since the children graph in this case has cycles, deep-printing hangs.

The context: I'm trying to rewrite ~1000 LOC of natvis into GDB pretty printers for TheDarkMod game, so that Linux programmers could enjoy debugging too. It looks like GDB normally assumes that children graph of any value is a tree and it can be deep-printed easily. But I feel such a restriction heavily limits the usefulness of natvis/pretty printers. Sadly, this issue looks like a blocker in using GDB pretty printers reliably.

As an unrelated issue, the limited natvis support also hangs on this repro project. To reproduce, run "Launch with natvis" configuration, then stop at the same breakpoint and look into Locals, then expand entity and renderParams.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne mit dem verknüpften Repro-Projekt, dem Breakpoint in main.cpp in badfunc, printers.py und der Konfiguration „Launch with pretty printers“; reproduziere den Hänger und untersuche den protokollierten -stack-list-arguments-Request. Vergleiche die Aufrufe der Pretty-Printer-Kinder mit den Debugger-Requests der Erweiterung und betrachte das Issue als gelöst, wenn der Breakpoint beim zyklischen Wert nicht mehr hängt und dabei das vorgesehene Locals-Verhalten erhalten bleibt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
cpp, python, typescript, vscode
Bereich
developer-experience, devtools
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Ruhig
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.