Type: Debugger
Describe the bug
I'm trying to write a SIGWINCH handler, but the process doesn't seem to receive the signal if I run it with the debugger. the program does work correctly if I run in terminal or with gdb in terminal.
Also this only happens with an external terminal, the internal one seems to work fine.
It's not a terminal specific problem, I tried it with Alacritty and xterm. Both show the same behaviour.
To Reproduce
Test program where the issue occurs:
#include <signal.h>
#include <sys/ioctl.h>
#include <iostream>
void sighandler(int n){
std::cout << "test" << std::endl;
}
int main(){
signal(SIGWINCH, sighandler);
getc(stdin);
return 0;
}
when I run this in terminal I get the output and resize the window I get
test
test
test
...
If I do the exact same program in the vscode debugger I get no output.
This is the launch config, basically just the default one:
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/test",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
@RensAlthuis Can you confirm that if you run it on the command line under gdb that it works fine also?
You can check your gdb's signal handling by adding info signals after you start it.
Conversely, you can add a setup command to send handle SIGWINCH pass during setup to pass the signal to the app.
This StackOverflow conversation might help: https://stackoverflow.com/questions/6136513/signals-when-debugging
@pieandcakes I did check it under commandline gdb, everything works normally in that case.
info signals SIGWINCH in gdb gives me this
Signal Stop Print Pass Hangup
SIGWINCH No No Yes Window size changed
Which seems correct. In vscode's debug console -exec info signals SIGWINCH gives me the same result.
I tried using handle SIGWINCH print in both the commandline and vscode.
gdb gives me Program received signal SIGWINCH, Window size changed. whenever I resize the terminal.
vscode's debug console doesn't seem to print anything.
@RensAlthuis That sounds like it is an issue with gdb when running under interpreter=mi mode.
Can you enable engineLogging in your launch.json and see if gdb emits anything regarding SIGWINCH?
@pieandcakes
Okay, I added "Logging":{"engineDebug":true} to the launch.json and tried again.
I can't find any reference to sigwinch (or signals in general in it) in the debug console.
I added the debug output below:
click here
1: (193) LaunchOptions<LocalLaunchOptions xmlns='http://schemas.microsoft.com/vstudio/MDDDebuggerOptions/2014'
1: (205) LaunchOptions ExePath='/home/rens/test/build/testprog'
1: (205) LaunchOptions WorkingDirectory='/home/rens/test'
1: (205) LaunchOptions ExeArguments=''
1: (205) LaunchOptions MIMode='gdb'
1: (206) LaunchOptions MIDebuggerPath=''
1: (206) LaunchOptions WaitDynamicLibLoad='false'
1: (206) LaunchOptions ExternalConsole='true'
1: (206) LaunchOptions>
1: (207) LaunchOptions <SetupCommands>
1: (207) LaunchOptions <Command IgnoreFailures='true' Description='Enable pretty-printing for gdb'>-enable-pretty-printing</Command>
1: (207) LaunchOptions </SetupCommands>
1: (207) LaunchOptions</LocalLaunchOptions>
1: (344) DbgCmd:echo $$ > /tmp/Microsoft-MIEngine-Pid-cfml2jhb.qjf ; cd /home/rens/test/build ; DbgTerm=`tty` ; set -o monitor ; trap 'rm /tmp/Microsoft-MIEngine-In-s0w09x9g.6gl /tmp/Microsoft-MIEngine-Out-2eruup3o.exw /tmp/Microsoft-MIEngine-Pid-cfml2jhb.qjf /tmp/Microsoft-MIEngine-Cmd-e43r7aj4.fx6' EXIT ; /usr/bin/gdb --interpreter=mi --tty=$DbgTerm < /tmp/Microsoft-MIEngine-In-s0w09x9g.6gl > /tmp/Microsoft-MIEngine-Out-2eruup3o.exw & clear; pid=$! ; echo $pid > /tmp/Microsoft-MIEngine-Pid-cfml2jhb.qjf ; wait $pid;
1: (365) Wait for connection completion.
1: (819) ->=thread-group-added,id="i1"
1: (821) ->~"GNU gdb (GDB) 8.2.1\n"
1: (823) ->~"Copyright (C) 2018 Free Software Foundation, Inc.\n"
1: (823) ->~"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law."
1: (824) ->~"\nType \"show copying\" and \"show warranty\" for details.\n"
1: (824) ->~"This GDB was configured as \"x86_64-pc-linux-gnu\".\n"
1: (824) ->~"Type \"show configuration\" for configuration details.\n"
1: (825) ->~"For bug reporting instructions, please see:\n"
1: (825) ->~"<http://www.gnu.org/software/gdb/bugs/>.\n"
1: (826) ->~"Find the GDB manual and other documentation resources online at:\n <http://www.gnu.org/software/gdb/documentation/>."
1: (826) ->~"\n\n"
1: (826) ->~"For help, type \"help\".\n"
1: (826) ->~"Type \"apropos word\" to search for commands related to \"word\".\n"
1: (827) ->(gdb)
1: (831) <-1001-gdb-set target-async on
1: (832) ->1001^done
1: (832) ->(gdb)
1: (834) 1001: elapsed time 3
1: (848) <-1002-enable-pretty-printing
1: (849) ->1002^done
1: (849) ->(gdb)
1: (849) 1002: elapsed time 1
1: (850) <-1003-interpreter-exec console "set pagination off"
1: (850) ->=cmd-param-changed,param="pagination",value="off"
1: (851) ->1003^done
1: (851) ->(gdb)
1: (851) 1003: elapsed time 1
1: (852) <-1004-gdb-set auto-solib-add on
1: (853) ->1004^done
1: (853) ->(gdb)
1: (854) 1004: elapsed time 2
1: (854) <-1005-gdb-set solib-search-path /home/rens/test/build:
1: (855) ->1005^done
1: (855) ->(gdb)
1: (857) 1005: elapsed time 1
1: (857) <-1006-gdb-set stop-on-solib-events 1
1: (857) ->1006^done
1: (858) ->(gdb)
1: (858) 1006: elapsed time 0
1: (858) <-1007-environment-cd /home/rens/test
1: (858) ->1007^done
1: (859) ->(gdb)
1: (859) 1007: elapsed time 0
1: (859) <-1008-file-exec-and-symbols /home/rens/test/build/testprog
1: (862) ->1008^done
1: (863) ->(gdb)
1: (863) 1008: elapsed time 3
1: (865) <-1009-interpreter-exec console "show architecture"
1: (865) ->~"The target architecture is set automatically (currently i386:x86-64)\n"
1: (866) ->1009^done
1: (866) ->(gdb)
1: (866) 1009: elapsed time 0
1: (868) <-1010-break-insert -f main
1: (869) ->1010^done,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x00000000000011c3",func="main()",file="/home/rens/test/test.cpp",fullname="/home/rens/test/test.cpp",line="12",thread-groups=["i1"],times="0",original-location="main"}
1: (869) ->(gdb)
1: (875) 1010: elapsed time 7
=thread-group-added,id="i1"
GNU gdb (GDB) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Warning: Debuggee TargetArchitecture not detected, assuming x86_64.
=cmd-param-changed,param="pagination",value="off"
1: (948) <-1011-exec-run
1: (949) ->=thread-group-started,id="i1",pid="2391"
1: (949) ->=thread-created,id="1",group-id="i1"
1: (957) ->=breakpoint-modified,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x00005555555551c3",func="main()",file="/home/rens/test/test.cpp",fullname="/home/rens/test/test.cpp",line="12",thread-groups=["i1"],times="0",original-location="main"}
1: (958) ->=library-loaded,id="/lib64/ld-linux-x86-64.so.2",target-name="/lib64/ld-linux-x86-64.so.2",host-name="/lib64/ld-linux-x86-64.so.2",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7fd5000",to="0x00007ffff7ff3784"}]
1: (960) <-1012-thread-info 1
1: (962) ->1011^running
1: (962) ->*running,thread-id="all"
1: (963) ->(gdb)
1: (964) ->1012^done,threads=[{id="1",target-id="process 2391",name="testprog",state="running",core="2"}]
1: (964) ->(gdb)
1: (964) ->~"Stopped due to shared library event (no libraries added or removed)\n"
1: (965) ->*stopped,reason="solib-event",thread-id="1",stopped-threads="all",core="2"
1: (967) 1011: elapsed time 18
1: (968) 1012: elapsed time 8
Stopped due to shared library event (no libraries added or removed)
1: (979) <-1013-interpreter-exec console "shell echo -e \\\\033c 1>&2"
1: (983) ->1013^done
1: (983) ->(gdb)
1: (983) 1013: elapsed time 4
1: (984) <-1014-gdb-set stop-on-solib-events 0
1: (984) ->1014^done
1: (984) ->(gdb)
1: (985) 1014: elapsed time 0
1: (990) <-1015-interpreter-exec console "info sharedlibrary"
1: (990) ->~"From To Syms Read Shared Object Library\n"
1: (991) ->~"0x00007ffff7fd5000 0x00007ffff7ff3784 Yes /lib64/ld-linux-x86-64.so.2\n"
1: (991) ->1015^done
1: (991) ->(gdb)
1: (991) 1015: elapsed time 1
Loaded '/lib64/ld-linux-x86-64.so.2'. Symbols loaded.
1: (997) <--exec-continue
1: (997) ->^running
1: (997) ->*running,thread-id="all"
1: (998) ->(gdb)
1: (999) ->=library-loaded,id="/usr/lib/libstdc++.so.6",target-name="/usr/lib/libstdc++.so.6",host-name="/usr/lib/libstdc++.so.6",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7e98020",to="0x00007ffff7f4fd73"}]
1: (999) ->=library-loaded,id="/usr/lib/libm.so.6",target-name="/usr/lib/libm.so.6",host-name="/usr/lib/libm.so.6",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7c97020",to="0x00007ffff7d3765b"}]
1: (1000) ->=library-loaded,id="/usr/lib/libgcc_s.so.1",target-name="/usr/lib/libgcc_s.so.1",host-name="/usr/lib/libgcc_s.so.1",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7c73020",to="0x00007ffff7c83d55"}]
1: (1000) ->=library-loaded,id="/usr/lib/libc.so.6",target-name="/usr/lib/libc.so.6",host-name="/usr/lib/libc.so.6",symbols-loaded="0",thread-group="i1",ranges=[{from="0x00007ffff7ace450",to="0x00007ffff7c1791f"}]
1: (1193) ->=breakpoint-modified,bkpt={number="1",type="breakpoint",disp="keep",enabled="y",addr="0x00005555555551c3",func="main()",file="/home/rens/test/test.cpp",fullname="/home/rens/test/test.cpp",line="12",thread-groups=["i1"],times="1",original-location="main"}
1: (1194) ->~"\n"
1: (1194) ->~"Breakpoint 1, main () at /home/rens/test/test.cpp:12\n"
Breakpoint 1, main () at /home/rens/test/test.cpp:12
1: (1194) ->~"12\t signal(SIGWINCH, sighandler);\n"
12 signal(SIGWINCH, sighandler);
1: (1194) ->*stopped,reason="breakpoint-hit",disp="keep",bkptno="1",frame={addr="0x00005555555551c3",func="main",args=[],file="/home/rens/test/test.cpp",fullname="/home/rens/test/test.cpp",line="12"},thread-id="1",stopped-threads="all",core="3"
1: (1207) <-1016-thread-info
1: (1208) ->1016^done,threads=[{id="1",target-id="process 2391",name="testprog",frame={level="0",addr="0x00005555555551c3",func="main",args=[],file="/home/rens/test/test.cpp",fullname="/home/rens/test/test.cpp",line="12"},state="stopped",core="3"}],current-thread-id="1"
1: (1208) ->(gdb)
1: (1209) 1016: elapsed time 2
1: (1221) <-1017-stack-list-frames 0 1000
1: (1221) ->1017^done,stack=[frame={level="0",addr="0x00005555555551c3",func="main",file="/home/rens/test/test.cpp",fullname="/home/rens/test/test.cpp",line="12"}]
1: (1221) ->(gdb)
1: (1223) 1017: elapsed time 2
1: (1230) <-1018-break-delete 1
1: (1230) ->1018^done
1: (1231) ->(gdb)
1: (1231) 1018: elapsed time 1
1: (1233) <--exec-continue
1: (1234) ->^running
1: (1234) ->*running,thread-id="all"
1: (1234) ->(gdb)
@RensAlthuis Can you do me a quick favor and not make your signal handler the first line of main and see if it works? We automatically set a breakpoint to stop at the first line of main to setup debugging and then automatically continue and I'm wondering if thats what is happening.
@pieandcakes Yeah, already did that to make sure that wasn't the problem.
I also tried setting stopAtEntry to true and then continuing execution from there, just to see if anything changed. But no luck.
@RensAlthuis if you add another line and then look at the log, do you see a SIGWINCH being fired? if not, then I think this is a gdb issue as it doesn't seem to be firing the signal under the MI interpreter.
My colleague had a suggestion that based on how we do stdin/stdout redirection to get everything to display properly, that might break this scenario too. He suggested to try launching your app (maybe have it wait on a cin) and then attaching to it and seeing if it would work.
@pieandcakes I don't see any SIGWINCH even with the extra line. I just tried running it with gdb --interpreter=mi in the commandline. That seems to work fine though I'm not sure if that proves anything?
@RensAlthuis Sorry, I edited the above comment. We think its because we have to do debugger/debuggee redirection for stdin/out to show up in a console that might be messing with it. can you try the attach scenario? If that works, then that will lead me to believe it is our redirections thats causing it not to work.
Unfortunately if that is the case, I don't think theres any way we can fix it for the extension.
@pieandcakes Interesting things happened
I tried running the program in a terminal and then running the debugger with this config
"configurations": [
{
"name": "(gdb) Attach",
"type": "cppdbg",
"request": "attach",
"program": "${workspaceFolder}/testprog",
"processId": "${command:pickProcess}",
"logging":{"engineLogging": true},
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
Then choosing testprog from the list.
It jumps to the vscode terminal with this message
$ env sh /tmp/Microsoft-MIEngine-Cmd-dseyclbm.dbg
"Superuser
/tmp/Microsoft-MIEngine-Cmd-dseyclbm.dbg: line 1: read: `process.': not a valid identifier
it pauses after "Superuser until I press any key, then it gives that error message.
So i tried running vscode as super user to see if that works, and that apparently works fine.
The process also receives the sigwinch signal in that case. But I presume that happens because the debugger is bypassed, there is no mention of sigwinch in the engineLogging stuff.
Honestly I'm already quite happy that I finally have a reasonable way of debugging my program now!
Anyway, thanks a lot. I really appreciate all the help.
@RensAlthuis thanks for following up. It isn't that it bypasses the debugger but since we aren't asking gdb to launch it and for the signals to make it through the redirections we use, it works.
@WardenGnaw If you can look and see why that error happens after picking the process?
@pieandcakes
So, I had some free time and decided to look in to this issue again. I found the problem, and came up with a solution. But it's rather convoluted and requires changes to the MIEngine (which you work on as well right?). I'm not really expecting you to read or do anything with this, I'm mostly just leaving this here if anyone else happens to run in to a similar problem and wants an explanation. I do suspect that these changes might solve a few other issues with linux signals as well.
When MIEngine starts gdb it does it with this command from UnixUtilities.cs in the MIEngines MICore code.
toggle command
```echo $$ > {pidFifo} ; cd {debuggeeDir} ; DbgTerm=`tty` ; set -o monitor ; trap 'rm {dbgStdInName} {dbgStdOutName} {pidFifo} {dbgCmdScript}' EXIT ; {debuggerCmd} {debuggerArgs} --tty=$DbgTerm < {dbgStdInName} > {dbgStdOutName} & clear; pid=$! ; echo $pid > {pidFifo} ; {waitForCompletionCommand}```
The issue is that --tty=$DbgTerm only works properly if the tty that $DbgTerm references is not a controlling terminal at that moment.
In this case there are two processes which belong to that session.
in order to use the --tty flag properly, both need to run without a controlling terminal.
This can be dealt with by changing gdb {args} --tty=blablabla to run as a daemon.
so setsid gdb {args} --tty= blablabla.
now this does break the pid=$! that comes after. so to fix that you could replace it with pid=`pidof -n gdb`. It's a bit slower but that should be fine.
to fix this we have to make sure we end the shell (it's no longer necessary), but not end the terminal window (by that I mean xterm and the like). Usually that is done by calling exec with some program. However, we can't run exec on wait $pid so this will take a bit more effort. An option is to replace wait with a program that removes its controlling terminal then waits for some process pid to terminate. something of a custom wait command. Executing that with exec [path/to/customwait] $pid should do the trick.
Toggle for example of custom wait program
It's unfortunate that the wait functions only work on childprocesses. That basically means the program has to keep checking whether the process is still running with kill(pid, 0). Maybe you could just wait forever and have either vscode or MIEngine send a sigterm to the terminal when gdb stops?/*exec [this_program] pid*/
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main (int argc, char** argv)
{
if(argc != 2)
return -1;
setbuf (stdout, NULL);
//to make sure TIOCNOTTY command doesn't kill this program
signal (SIGHUP, SIG_IGN);
//make sure this program is the only process in the session
if (ioctl (STDIN_FILENO, TIOCSCTTY, 0) != 0)
return -1;
//remove the controlling terminal
if (ioctl (STDIN_FILENO, TIOCNOTTY) != 0)
return -1;
//get the pid from commandline
pid_t pid = atoi(argv[1]);
//very inefficiently wait for the pid to terminate
//also subject to race conditions.
//As another program might claim the pid during the sleep
//But that is unlikely and not a really a big problem.
while(kill(pid, 0) == 0)
sleep(0.2);
return 0;
}
making these changes works, at least when I test it on my machine. I don't see any reason this won't work the same for any linux machine. maybe even for mac?
I'd make a pull request on the MIEngine for this, but I'm not sure how to get MIEngine to include and compile a c program.
Besides I doubt my code is good enough since I don't know how to test this for any other systems, I only have my laptop to test on. So feel free to ignore this, but if you have some time to spend.
Also as an aside, that means that in vscode's source in this file src/vs/workbench/parts/execution/electron-browser/terminalService.ts
line 243:
const bashCommand = `${quote(args)}; echo; read -p "${LinuxTerminalService.WAIT_MESSAGE}" -n1;`;
It will never reach the echo; .... since the terminal alerady terminates in the ${quote(args)} bit.
so it could be changed to just this.
const bashCommand = ${quote(args)};
I don't see why the terminal needs to wait for a key stroke to close in the first place.
EDIT:
turns out that last change to visual studio code's source is actually required, though i'm not entirely sure why. I think if you leave the part after ${quote(args)} in, it keeps the shell bash shell alive.
@RensAlthuis Thank you for investigating further and updating this issue. The C++ extension also uses MIEngine as the debug adapter to communicate between VS Code and gdb or lldb.
I'll take a look at your comment and see what we can do.
As for the VS Code side, I assume they have the terminal waiting for a key stroke to prevent it from closing after a debuggee's execution has ended. This seems to be a request from many people new to console debugging in general.
I get
$ env sh /tmp/Microsoft-MIEngine-Cmd-wn924gm2.kaq
"Superuser
until I press a key, then the terminal shows
$ env sh /tmp/Microsoft-MIEngine-Cmd-wn924gm2.kaq
"Superuser
/tmp/Microsoft-MIEngine-Cmd-wn924gm2.kaq: line 1: read: `process.': not a valid identifier
I am using attach with an explicit process id, no selection dialog.
Same issue? Any workaround aside from running sudo code .?
I have the exact same problem as you @davidsgrogan
If you find a solution, please let me know.
I have the same issue. If I go into the _/tmp/Microsoft-MIEngine-Cmd-wn924gm2.kaq_ and swap the escaped double quotes here _...\"Superuser..._ and here _...Do you want to continue? [y/N]\"..._ with single quotes. I can call the command "env sh /tmp/Microsoft-MIEngine-Cmd-wn924gm2.kaq " succesfully. I think the temprorary script _Microsoft-MIEngine-Cmd-wn924gm2.kaq_ might be created with an error causing this bug. I couldn't find where this script is created so I couldn't attempt to fix it but maybe this info is helpful to you.
@davidsgrogan @Thalley @ozbeka Your issue is different than the reported issue here. Theres a similar issue (https://github.com/microsoft/vscode-cpptools/issues/3711) that will track the sudo problem you are reporting.
This issue has been closed automatically because it has not had recent activity.
Most helpful comment
@pieandcakes
So, I had some free time and decided to look in to this issue again. I found the problem, and came up with a solution. But it's rather convoluted and requires changes to the MIEngine (which you work on as well right?). I'm not really expecting you to read or do anything with this, I'm mostly just leaving this here if anyone else happens to run in to a similar problem and wants an explanation. I do suspect that these changes might solve a few other issues with linux signals as well.
Actual problem
When MIEngine starts gdb it does it with this command from UnixUtilities.cs in the MIEngines MICore code.
toggle command
```echo $$ > {pidFifo} ; cd {debuggeeDir} ; DbgTerm=`tty` ; set -o monitor ; trap 'rm {dbgStdInName} {dbgStdOutName} {pidFifo} {dbgCmdScript}' EXIT ; {debuggerCmd} {debuggerArgs} --tty=$DbgTerm < {dbgStdInName} > {dbgStdOutName} & clear; pid=$! ; echo $pid > {pidFifo} ; {waitForCompletionCommand}```
The issue is that
--tty=$DbgTermonly works properly if the tty that $DbgTerm references is not a controlling terminal at that moment.In this case there are two processes which belong to that session.
in order to use the --tty flag properly, both need to run without a controlling terminal.
dealing with gdb
This can be dealt with by changing
gdb {args} --tty=blablablato run as a daemon.so
setsid gdb {args} --tty= blablabla.now this does break the
pid=$!that comes after. so to fix that you could replace it withpid=`pidof -n gdb`. It's a bit slower but that should be fine.dealing with the shell process
to fix this we have to make sure we end the shell (it's no longer necessary), but not end the terminal window (by that I mean xterm and the like). Usually that is done by calling exec with some program. However, we can't run exec on
wait $pidso this will take a bit more effort. An option is to replace wait with a program that removes its controlling terminal then waits for some process pid to terminate. something of a custom wait command. Executing that withexec [path/to/customwait] $pidshould do the trick.Toggle for example of custom wait program
It's unfortunate that the wait functions only work on childprocesses. That basically means the program has to keep checking whether the process is still running with
kill(pid, 0). Maybe you could just wait forever and have either vscode or MIEngine send a sigterm to the terminal when gdb stops?conclusion
making these changes works, at least when I test it on my machine. I don't see any reason this won't work the same for any linux machine. maybe even for mac?
I'd make a pull request on the MIEngine for this, but I'm not sure how to get MIEngine to include and compile a c program.
Besides I doubt my code is good enough since I don't know how to test this for any other systems, I only have my laptop to test on. So feel free to ignore this, but if you have some time to spend.
Also as an aside, that means that in vscode's source in this file
src/vs/workbench/parts/execution/electron-browser/terminalService.tsline 243:
const bashCommand = `${quote(args)}; echo; read -p "${LinuxTerminalService.WAIT_MESSAGE}" -n1;`;It will never reach the
echo; .... since the terminal alerady terminates in the ${quote(args)} bit.so it could be changed to just this.
const bashCommand =
${quote(args)};I don't see why the terminal needs to wait for a key stroke to close in the first place.
EDIT:
turns out that last change to visual studio code's source is actually required, though i'm not entirely sure why. I think if you leave the part after ${quote(args)} in, it keeps the shell bash shell alive.