Skip to content

Conversation

@jquast
Copy link
Contributor

@jquast jquast commented Oct 31, 2025

Interactive terminal sequence response for DEC Private Mode Query is invalid -- it may respond with a different mode and status than the one requested.

This causes programs to fail or mismatch contour's terminal capabilities. In my API I was expecting the requested mode value in the response and, not matching it for any modes under number 27, wrongly reported that Contour does not support any DEC Private Modes at all.

This bug is present in all versions of Contour supporting DEC Private Mode, since 256e313 and refactored in faa66e7, the use of:

   static_cast<DECMode>(mode)

Is invalid, because the DECMode enum has "holes". It is not contiguous.

A new fromDECModeNum() function is provided, refactored form of isValidDecMode() -- returning an optional DecMode, existing function isValidDECMode() is refactored to check whether the optional value returned by 'fromDECModeNum' tests true for has_value().

Given the provided test file test/display-modes.sh, we can make inquiry of DEC Private modes and see that DEC modes 1 through 27 are returned with non-matching response modes mismatched by enum item order and status:

$ ./test/display-modes.sh
Query mode 1: response=$'\E[?2;2$y' after 13ms
Query mode 2: response=$'\E[?3;2$y' after 11ms
Query mode 3: response=$'\E[?4;2$y' after 10ms
Query mode 4: response=$'\E[?5;2$y' after 11ms
Query mode 5: response=$'\E[?9;2$y' after 11ms
Query mode 6: response=$'\E[?1000;2$y' after 12ms
Query mode 7: response=$'\E[?1001;2$y' after 13ms
Query mode 8: response=$'\E[?1002;2$y' after 13ms
Query mode 9: response=$'\E[?1003;2$y' after 12ms
Query mode 10: response=$'\E[?1048;2$y' after 14ms

After this bugfix, this is corrected:

$ ./test/display-modes.sh
Query mode 1: response=$'\E[?1;2$y' after 11ms
Query mode 2: response=$'\E[?2;2$y' after 11ms
Query mode 3: response=$'\E[?3;2$y' after 8ms
Query mode 4: response=$'\E[?4;2$y' after 10ms
Query mode 5: response=$'\E[?5;2$y' after 8ms
Query mode 6: response=$'\E[?6;2$y' after 11ms
Query mode 7: response=$'\E[?7;1$y' after 11ms
Query mode 8: response=$'\E[?8;0$y' after 10ms
Query mode 9: response=$'\E[?9;2$y' after 10ms
Query mode 10: response=$'\E[?10;2$y' after 12ms

Further, looking at other uses of isValidDECMode(), some were unnecessary -- that they have the DECMode type bound to the variable is sufficient enough to describe that mode as valid, the check is superfluous and removed, eg:

  isValidDECMode(static_cast<unsigned int>(mode)));

the call to toDECModeNum is also superfluous and removed.

@github-actions github-actions bot added the VT: Backend Virtual Terminal Backend (libterminal API) label Oct 31, 2025
@jquast jquast force-pushed the jq/bugfix-request-dec-mode branch from 785ce7c to bd0b7a2 Compare October 31, 2025 01:26
Copy link
Member

@christianparpart christianparpart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks for the fix. Is it okay to apply the minors, for you?

jquast and others added 2 commits November 2, 2025 18:26
Interactive terminal sequence response for DEC Private Mode Query is
invalid -- it may respond with a different mode and status than the one
requested.

This causes programs to fail or mismatch contour's terminal
capabilities. In my API I was expecting the requested mode value in the
response pattern, and, not discovering it after some timeout, wrongly
reported that Contour does not support any DEC Private Modes at all.

This bug is present in all versions of Contour supporting DEC Private
Mode, since 256e313 and refactored in faa66e7, the use of:

       static_cast<DECMode>(mode)

Is invalid, because the DECMode enum has "holes". It is not contiguous.

A new 'fromDECModeNum' function is provided, returning an optional
DecMode, and, existing function 'isValidDECMode' is refactored to check
whether the optional value returned by 'fromDECModeNum' has_value().

Given the provided file `test/display-modes.sh`, we can make inquiry of
DEC Private modes and see that DEC modes 1 through 27 are returned with
non-matching response modes mismatched by enum item order and status::

    $ ./test/display-modes.sh
    Query mode 1: response=$'\E[?2;2$y' after 13ms
    Query mode 2: response=$'\E[?3;2$y' after 11ms
    Query mode 3: response=$'\E[?4;2$y' after 10ms
    Query mode 4: response=$'\E[?5;2$y' after 11ms
    Query mode 5: response=$'\E[?9;2$y' after 11ms
    Query mode 6: response=$'\E[?1000;2$y' after 12ms
    Query mode 7: response=$'\E[?1001;2$y' after 13ms
    Query mode 8: response=$'\E[?1002;2$y' after 13ms
    Query mode 9: response=$'\E[?1003;2$y' after 12ms
    Query mode 10: response=$'\E[?1048;2$y' after 14ms

After this bugfix, this is corrected:

    $ ./test/display-modes.sh
    Query mode 1: response=$'\E[?1;2$y' after 11ms
    Query mode 2: response=$'\E[?2;2$y' after 11ms
    Query mode 3: response=$'\E[?3;2$y' after 8ms
    Query mode 4: response=$'\E[?4;2$y' after 10ms
    Query mode 5: response=$'\E[?5;2$y' after 8ms
    Query mode 6: response=$'\E[?6;2$y' after 11ms
    Query mode 7: response=$'\E[?7;1$y' after 11ms
    Query mode 8: response=$'\E[?8;0$y' after 10ms
    Query mode 9: response=$'\E[?9;2$y' after 10ms
    Query mode 10: response=$'\E[?10;2$y' after 12ms

Further, looking at other uses of 'isValidDECMode', some were unnecessary,
that they have the DECMode type bound to the variable is sufficient
to describe that mode as valid for Contour, the check is superfluous:

      isValidDECMode(static_cast<unsigned int>(mode)));
Signed-off-by: Christian Parpart <[email protected]>
@christianparpart christianparpart force-pushed the jq/bugfix-request-dec-mode branch from 58856f8 to 7467a30 Compare November 2, 2025 17:29
…oid some code duplication

Signed-off-by: Christian Parpart <[email protected]>
@github-actions github-actions bot added test Unit tests CI GitHub Actions & CI labels Nov 2, 2025
@christianparpart christianparpart force-pushed the jq/bugfix-request-dec-mode branch from 9b66e21 to 48999ce Compare November 2, 2025 20:11
@christianparpart christianparpart force-pushed the jq/bugfix-request-dec-mode branch from 48999ce to 6ce2956 Compare November 2, 2025 20:17
Copy link
Member

@christianparpart christianparpart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for your contribution, @jquast 😄

@christianparpart christianparpart merged commit b2c0b5f into contour-terminal:master Nov 2, 2025
26 of 27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI GitHub Actions & CI test Unit tests VT: Backend Virtual Terminal Backend (libterminal API)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants