microsoft / microsoft/vscode-cpptools
GDB hangs on breakpoint, infinitely traversing pretty printers
Nessuno ha ancora preso questa issue.
- Lingua principale
- TypeScript
- Stelle
- 6.2k
- Fork
- 1.7k
- Merge medio
- 14h 46m
- PR unite (30g)
- 61
Descrizione
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:
- Clone this repository: https://github.com/stgatilov/vscode-gdb-pretty-printers-hangs-repro-code
- Open it in VS Code.
- Build Debug build.
- Put breakpoint at the only line of
badfunc. - Run debugging using the included configuration "Launch with pretty printers".
- 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.
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Direzione di ricerca
Inizia dal progetto di riproduzione collegato, dal breakpoint di main.cpp in badfunc, da printers.py e dalla configurazione “Launch with pretty printers”; riproduci il blocco e analizza la richiesta -stack-list-arguments registrata. Confronta le chiamate ai figli del pretty-printer con le richieste del debugger dell’estensione e considera risolta l’issue quando il breakpoint non si blocca più sul valore ciclico, preservando al contempo il comportamento previsto di Locals.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- cpp, python, typescript, vscode
- Ambito
- developer-experience, devtools
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Da chiarire
- Idoneità per principianti
- 35/100