Repeated use of OSC4 causes output corruption #15099

Closed
opened 2026-01-31 04:28:32 +00:00 by claunia · 8 comments
Owner

Originally created by @vefatica on GitHub (Sep 5, 2021).

Windows Terminal version (or Windows build number)

Microsoft Windows 10 Pro for Workstations 10.0.19043.1165 (2009, 21H1)

Other Software

Batch files in TCC.EXE

Steps to reproduce

I wrote an app to reset the 16-color console palette reproduce any of WT's nine "schemes". It constructs the OSC4 sequence without ESCs, outputs it (error checking), and issues it with the ESCs added. At it's heart is this (full CPP attached).

	for ( INT i=0; i<16; i++ ) // Does conhost have colors 16 and 17?
	{
		// they're backwards
		r = GetBValue(cr[index][i]);
		g = GetGValue(cr[index][i]);
		b = GetRValue(cr[index][i]);
		wsprintfW(seq, L"]4;%d;rgb:%02X/%02X/%02X", i, r, g, b);
		WriteConsoleW(hOut, seq, lstrlen(seq), &dwWritten, nullptr);
		WriteConsoleW(hOut, L"\r\n", lstrlen(L"\r\n"), &dwWritten, nullptr);
		wsprintfW(seq2, L"%c%s%c", L'\x01b', seq, L'\x01b');
		WriteConsoleW(hOut, seq2, lstrlen(seq2), &dwWritten, nullptr);
	}

The program works, but I see corrupted output. Here's the result when run in the general audience CMD/CONHOST (scheme 8 is "Vintage", my default for consoles). Notice that after OSC4 has been issued once, the subsequent test output is corrupt (missing the leading ']'). Aside from that, the app works.

D:\Projects2019\osc4test\x64\Release> osc4test.exe 8
]4;0;rgb:00/00/00
4;1;rgb:80/00/00
4;2;rgb:00/80/00
4;3;rgb:80/80/00
4;4;rgb:00/00/80
4;5;rgb:80/00/80
4;6;rgb:00/80/80
4;7;rgb:C0/C0/C0
4;8;rgb:80/80/80
4;9;rgb:FF/00/00
4;10;rgb:00/FF/00
4;11;rgb:FF/FF/00
4;12;rgb:00/00/FF
4;13;rgb:FF/00/FF
4;14;rgb:00/FF/FF
4;15;rgb:FF/FF/FF

Exactly the same thing happens if I do it in a batch file with this loop at its heart.

:: envvar x is scheme index; i is color index
:: entries in array a look like RRGGBB (hex)
do i=0 to 15
	set r=%@instr[0,2,%a[%x,%i]]
	set g=%@instr[2,2,%a[%x,%i]]
	set b=%@instr[4,2,%a[%x,%i]]
	set seq=]4;%i;rgb:%r/%g/%b
	echo %seq
	echos ^e%seq^e
enddo

Things get worse if I run the EXE in a current OpenConsole.exe (stable or preview) and CMD. All output after the first line is lost. Likewise for the batch file with TCC.EXE running in OpenConsole.exe.

p:\osc4test\x64\Release> osc4test.exe 8
]4;0;rgb:00/00/00

p:\osc4test\x64\Release>

osc4test.src.zip

Expected Behavior

No corruption.

Actual Behavior

As described above.

Originally created by @vefatica on GitHub (Sep 5, 2021). ### Windows Terminal version (or Windows build number) Microsoft Windows 10 Pro for Workstations 10.0.19043.1165 (2009, 21H1) ### Other Software Batch files in TCC.EXE ### Steps to reproduce I wrote an app to reset the 16-color console palette reproduce any of WT's nine "schemes". It constructs the OSC4 sequence without ESCs, outputs it (error checking), and issues it with the ESCs added. At it's heart is this (full CPP attached). ``` for ( INT i=0; i<16; i++ ) // Does conhost have colors 16 and 17? { // they're backwards r = GetBValue(cr[index][i]); g = GetGValue(cr[index][i]); b = GetRValue(cr[index][i]); wsprintfW(seq, L"]4;%d;rgb:%02X/%02X/%02X", i, r, g, b); WriteConsoleW(hOut, seq, lstrlen(seq), &dwWritten, nullptr); WriteConsoleW(hOut, L"\r\n", lstrlen(L"\r\n"), &dwWritten, nullptr); wsprintfW(seq2, L"%c%s%c", L'\x01b', seq, L'\x01b'); WriteConsoleW(hOut, seq2, lstrlen(seq2), &dwWritten, nullptr); } ``` The program works, but I see corrupted output. Here's the result when run in the general audience CMD/CONHOST (scheme 8 is "Vintage", my default for consoles). Notice that after OSC4 has been issued once, the subsequent test output is corrupt (missing the leading ']'). Aside from that, the app works. ``` D:\Projects2019\osc4test\x64\Release> osc4test.exe 8 ]4;0;rgb:00/00/00 4;1;rgb:80/00/00 4;2;rgb:00/80/00 4;3;rgb:80/80/00 4;4;rgb:00/00/80 4;5;rgb:80/00/80 4;6;rgb:00/80/80 4;7;rgb:C0/C0/C0 4;8;rgb:80/80/80 4;9;rgb:FF/00/00 4;10;rgb:00/FF/00 4;11;rgb:FF/FF/00 4;12;rgb:00/00/FF 4;13;rgb:FF/00/FF 4;14;rgb:00/FF/FF 4;15;rgb:FF/FF/FF ``` Exactly the same thing happens if I do it in a batch file with this loop at its heart. ``` :: envvar x is scheme index; i is color index :: entries in array a look like RRGGBB (hex) do i=0 to 15 set r=%@instr[0,2,%a[%x,%i]] set g=%@instr[2,2,%a[%x,%i]] set b=%@instr[4,2,%a[%x,%i]] set seq=]4;%i;rgb:%r/%g/%b echo %seq echos ^e%seq^e enddo ``` Things get worse if I run the EXE in a current OpenConsole.exe (stable or preview) and CMD. All output after the first line is lost. Likewise for the batch file with TCC.EXE running in OpenConsole.exe. ``` p:\osc4test\x64\Release> osc4test.exe 8 ]4;0;rgb:00/00/00 p:\osc4test\x64\Release> ``` [osc4test.src.zip](https://github.com/microsoft/terminal/files/7112030/osc4test.src.zip) ### Expected Behavior No corruption. ### Actual Behavior As described above.
claunia added the Resolution-Fix-AvailableNeeds-TriageIssue-Docs labels 2026-01-31 04:28:32 +00:00
Author
Owner

@j4james commented on GitHub (Sep 6, 2021):

The OSC sequence needs to be terminated with "\x1b\\" (i.e. escape + backslash).

The behaviour you're seeing in OpenConsole is correct. When the escape isn't followed by a backslash, it's interpreted as the start of a new escape sequence. And since you then follow that with the introducer for an OSC, that text is also going to be interpreted as an OSC sequence and consumed up to the next escape. And this process just keeps repeating itself until all of the output is consumed.

The error handling in the older versions of conhost wasn't quite correct, so you're seeing a different result there, but if you terminated your OSC sequence correctly, it should work in both versions.

@j4james commented on GitHub (Sep 6, 2021): The `OSC` sequence needs to be terminated with `"\x1b\\"` (i.e. escape + backslash). The behaviour you're seeing in OpenConsole is correct. When the escape isn't followed by a backslash, it's interpreted as the start of a new escape sequence. And since you then follow that with the introducer for an `OSC`, that text is also going to be interpreted as an `OSC` sequence and consumed up to the next escape. And this process just keeps repeating itself until all of the output is consumed. The error handling in the older versions of conhost wasn't quite correct, so you're seeing a different result there, but if you terminated your `OSC` sequence correctly, it should work in both versions.
Author
Owner

@vefatica commented on GitHub (Sep 6, 2021):

Thanks, @j4james. Maybe that belongs in https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences (where I get my info). That doc doesn't show a trailing backslash. Or is there something more general that I should have known about?

@vefatica commented on GitHub (Sep 6, 2021): Thanks, @j4james. Maybe that belongs in [https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) (where I get my info). That doc doesn't show a trailing backslash. Or is there something more general that I should have known about?
Author
Owner

@j4james commented on GitHub (Sep 6, 2021):

OK, I never noticed that before. That's definitely a bug in the docs. If you're feeling enthusiastic, you can file a report on the documentation issue tracker - there's a link to it at the bottom of the page.

And for future reference, you're probably better off using the Xterm control sequence documentation here:
https://invisible-island.net/xterm/ctlseqs/ctlseqs.html

We don't support everything that Xterm does, but you can see a list of the sequences we do support here:
https://terminalnuget.blob.core.windows.net/packages/TerminalSequences.html

I'm not sure that's completely up to date either, but it'll be better than the microsoft.com documentation.

@j4james commented on GitHub (Sep 6, 2021): OK, I never noticed that before. That's definitely a bug in the docs. If you're feeling enthusiastic, you can file a report on the documentation issue tracker - there's a link to it at the bottom of the page. And for future reference, you're probably better off using the Xterm control sequence documentation here: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html We don't support everything that Xterm does, but you can see a list of the sequences we do support here: https://terminalnuget.blob.core.windows.net/packages/TerminalSequences.html I'm not sure that's completely up to date either, but it'll be better than the microsoft.com documentation.
Author
Owner

@vefatica commented on GitHub (Sep 6, 2021):

Thanks again, @j4james. I filed a report.

Curious ... do you know why ESC \ was chosen as the terminator instead of, say, BEL or ST (which seem to be more normal)?

@vefatica commented on GitHub (Sep 6, 2021): Thanks again, @j4james. I filed a report. Curious ... do you know why `ESC \` was chosen as the terminator instead of, say, BEL or ST (which seem to be more normal)?
Author
Owner

@j4james commented on GitHub (Sep 6, 2021):

ESC \ is actually ST! It's just the 7-bit equivalent of the 8-bit C1 control (see here). You can also use the C1 control itself, but in UTF-8 it's not saving you anything, and probably isn't as widely supported (we only added support for it recently I believe). And BEL is a non-standard string terminator, so isn't recommended, but we do support that too (only with OSC controls though).

@j4james commented on GitHub (Sep 6, 2021): `ESC \` is actually `ST`! It's just the 7-bit equivalent of the 8-bit C1 control (see [here](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-C1-_8-Bit_-Control-Characters)). You can also use the C1 control itself, but in UTF-8 it's not saving you anything, and probably isn't as widely supported (we only added support for it recently I believe). And `BEL` is a non-standard string terminator, so isn't recommended, but we do support that too (only with `OSC` controls though).
Author
Owner

@vefatica commented on GitHub (Sep 6, 2021):

Thanks for that link (7/8-bit C1). I'd seen stuff like that before but never really caught on. Now I get it ... 7-bit equivalents of 8-bit thingies.

@vefatica commented on GitHub (Sep 6, 2021): Thanks for that link (7/8-bit C1). I'd seen stuff like that before but never really caught on. Now I get it ... 7-bit equivalents of 8-bit thingies.
Author
Owner

@DHowett commented on GitHub (Sep 7, 2021):

(I believe that the bug on our documentation site is because the markdown parser consumed the \ and treated it as an escaping character 😁)

@DHowett commented on GitHub (Sep 7, 2021): (I believe that the bug on our documentation site is because the markdown parser consumed the `\` and treated it as an escaping character :grin:)
Author
Owner

@zadjii-msft commented on GitHub (Sep 18, 2021):

Looks like this was fixed in https://github.com/MicrosoftDocs/Console-Docs/pull/221

@zadjii-msft commented on GitHub (Sep 18, 2021): Looks like this was fixed in https://github.com/MicrosoftDocs/Console-Docs/pull/221
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#15099