Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VT parser for erase operations needs to be able to handle multiple arguments #2101

Closed
PankajBhojwani opened this issue Jul 25, 2019 · 2 comments · Fixed by #7799
Closed

VT parser for erase operations needs to be able to handle multiple arguments #2101

PankajBhojwani opened this issue Jul 25, 2019 · 2 comments · Fixed by #7799
Labels
Area-VT Virtual Terminal sequence support Help Wanted We encourage anyone to jump in on these. Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.

Comments

@PankajBhojwani
Copy link
Contributor

Currently, _GetEraseOperation in OutputStateMachineEngine.cpp cannot handle input sequences which are meant to call the same erase operation more than once but with different erase types. For example, it cannot handle "]3;J" or "]3;2J". Upon receiving these kinds of inputs the function fails to convert the parameters into their respective erase types and the erase operation is not called at all.

This can be fixed by changing the output memory location to be an array of erase types instead of just a single erase type, and the function would then add erase types to that array as it loops through the input parameters.

Changes that would need to be made elsewhere to accommodate this change:

  • the erase operations themselves (in adaptDispatch and TerminalDispatch) would need to be changed to accept an array of erase types - they would then have to loop through the array and perform the required operations
  • the unit tests that call these functions would need to be updated
  • possibly other changes too
@ghost ghost added Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels Jul 25, 2019
@PankajBhojwani PankajBhojwani added Area-VT Virtual Terminal sequence support Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal. labels Jul 25, 2019
@ghost ghost removed the Needs-Tag-Fix Doesn't match tag requirements label Jul 25, 2019
@PankajBhojwani PankajBhojwani added the Help Wanted We encourage anyone to jump in on these. label Jul 25, 2019
@j4james
Copy link
Collaborator

j4james commented Jul 27, 2019

Note that there are two related issues at work here.

  1. Most, if not all, single parameter commands should work with multiple parameters, assuming we want to match the behaviour of XTerm (I don't know if there is spec text to back this up). For example, consider this sequence:

    printf "X \e[5;10B Y\n"
    

    In XTerm that outputs the X and Y 5 lines apart. Even the though the Cursor Down command only takes one parameter, it still considers that a valid sequences and just ignores any additional parameters.

  2. Some commands, like Erase in Line and Erase in Display, are specifically documented as taking multiple parameters, even though they may appear to need only one. For these sequences, every one of the parameters should be processed in turn. So if you look at this sequence:

    printf "xxxxxxyyyyyy\b\b\b\b\b\b\e[0;1K\n" 
    

    Both parameters should be processed, so technically it should clear to both the beginning and the end of the line. However this behaviour was only documented for later VT terminals, as far as I can tell, and doesn't appear to be widely supported.

My point being that the first case is more important than the second, but also applies to far more than just the erase commands. The second case I would consider less of a priority, since I don't think even XTerm supports that.

@DHowett-MSFT DHowett-MSFT removed the Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting label Jul 29, 2019
@DHowett-MSFT DHowett-MSFT added this to the Console Backlog milestone Jul 29, 2019
@ghost ghost added the In-PR This issue has a related PR label Oct 1, 2020
@ghost ghost closed this as completed in #7799 Oct 15, 2020
@ghost ghost added Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. and removed In-PR This issue has a related PR labels Oct 15, 2020
ghost pushed a commit that referenced this issue Oct 15, 2020
This PR introduces a pair of classes for managing VT parameters that
automatically handle range checking and default fallback values, so the
individual operations don't have to do that validation themselves. In
addition to simplifying the code, this fixes a few cases where we were
mishandling missing or extraneous parameters, and adds support for
parameter sequences on commands that couldn't previously handle them.
This PR also sets a limit on the number of parameters allowed, to help
thwart DoS memory consumption attacks.

## References

* The new parameter class also introduces the concept of an
  omitted/default parameter which is not necessarily zero, which is a
  prerequisite for addressing issue #4417.

## Detailed Description of the Pull Request / Additional comments

There are two new classes provide by this PR: a `VTParameter` class,
similar in function to a `std::optional<size_t>`, which holds an
individual parameter (which may be an omitted/default value); and a
`VTParameters` class, similar in function to `gsl:span<VTParameter>`,
which holds a sequence of those parameters.

Where `VTParameter` differs from `std::optional` is with the inclusion
of two cast operators. There is a `size_t` cast that interprets omitted
and zero values as 1 (the expected behaviour for most numeric
parameters). And there is a generic cast, for use with the enum
parameter types, which interprets omitted values as 0 (the expected
behaviour for most selective parameters).

The advantage of `VTParameters` class is that it has an `at` method that
can never fail - out of range values simply return the a default
`VTParameter` instance (this is standard behaviour in VT terminals). It
also has a `size` method that will always return a minimum count of 1,
since an empty parameter list is typically the equivalent of a single
"default" parameter, so this guarantees you'll get at least one value
when iterating over the list with `size()`.

For cases where we just need to call the same dispatch method for every
parameter, there is a helper `for_each` method, which repeatedly calls a
given predicate function with each value in the sequence. It also
collates the returned success values to determine the overall result of
the sequence. As with the `size` method, this will always make at least
one call, so it correctly handles empty sequences.

With those two classes in place, we could get rid of all the parameter
validation and default handling code in the `OutputStateMachineEngine`.
We now just use the `VTParameters::at` method to grab a parameter and
typically pass it straight to the appropriate dispatch method, letting
the cast operators automatically handle the assignment of default
values. Occasionally we might need a `value_or` call to specify a
non-standard default value, but those cases are fairly rare.

In some case the `OutputStateMachineEngine` was also checking whether
parameters values were in range, but for the most part this shouldn't
have been necessary, since that is something the dispatch classes would
already have been doing themselves (in the few cases that they weren't,
I've now updated them to do so).

I've also updated the `InputStateMachineEngine` in a similar way to the
`OutputStateMachineEngine`, getting rid of a few of the parameter
extraction methods, and simplifying other parts of the implementation.
It's not as clean a replacement as the output engine, but there are
still benefits in using the new classes.

## Validation Steps Performed

For the most part I haven't had to alter existing tests other than
accounting for changes to the API. There were a couple of tests I needed
to drop because they were checking for failure cases which shouldn't
have been failing (unexpected parameters should never be an error), or
testing output engine validation that is no longer handled at that
level.

I've added a few new tests to cover operations that take sequences of
selective parameters (`ED`, `EL`, `TBC`, `SM`, and `RM`). And I've
extended the cursor movement tests to make sure those operations can
handle extraneous parameters that weren't expected. I've also added a
test to verify that the state machine will correctly ignore parameters
beyond the maximum 32 parameter count limit.

I've also manual confirmed that the various test cases given in issues
#2101 are now working as expected.

Closes #2101
@ghost
Copy link

ghost commented Nov 11, 2020

🎉This issue was addressed in #7799, which has now been successfully released as Windows Terminal Preview v1.5.3142.0.:tada:

Handy links:

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-VT Virtual Terminal sequence support Help Wanted We encourage anyone to jump in on these. Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants