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

Fixed size comparisons that could lead to infinite loops #18451

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

javierdlg
Copy link
Member

@javierdlg javierdlg commented Jan 22, 2025

Summary of the Pull Request

After taking in 1.22, our CodeQL process caught a few locations where we were performing integer comparisons of different sizes which could lead to an infinite loop if the larger integer goes out of range of the smaller integer.

For example, comparing uint8_t < size_t works until size_t goes above 256, where no matter how much we change uin8_t we will never reach 256

References and Relevant Issues

CodeQL issues:
https://liquid.microsoft.com/codeql/issues/5f2b05d5-9e87-4df4-b493-f00e710d38df?copilot_promptid=E91B0CE9-0C1B-4AC2-8A46-33F49B67E058
https://liquid.microsoft.com/codeql/issues/76268284-2d4b-4b10-8aff-a947ecc1a576?copilot_promptid=E91B0CE9-0C1B-4AC2-8A46-33F49B67E058
https://liquid.microsoft.com/codeql/issues/452f966b-5b99-420e-96c0-153caea2a0b4?copilot_promptid=E91B0CE9-0C1B-4AC2-8A46-33F49B67E058

Detailed Description of the Pull Request / Additional comments

I used saturated_cast<> for these changes to make overflow values equal to the max value of the smallest integer.

Validation Steps Performed

PR Checklist

  • Closes #xxx
  • Tests added/passed
  • Documentation updated
    • If checked, please file a pull request on our docs repo and link it here: #xxx
  • Schema updated (if necessary)

@javierdlg javierdlg requested a review from DHowett January 22, 2025 17:34
@javierdlg javierdlg self-assigned this Jan 22, 2025
Comment on lines 611 to 615
if (_conformanceLevel <= 3 && _maxColors > 2 && _colorTableChanged) [[unlikely]]
{
for (IndexType tableIndex = 0; tableIndex < _maxColors; tableIndex++)
// _maxColors is 64-bit and tableIndex is 8-bit. If _maxColors is higher
// than the 8-bit integer limit, we will loop indefinitely.
for (IndexType tableIndex = 0; tableIndex < (saturated_cast<uint8_t>(_maxColors)); tableIndex++)
Copy link
Collaborator

Choose a reason for hiding this comment

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

In this situation _maxColors will never be greater than 16, because that's the maximum value for conformance level 3 (which we're checking in the condition above). Would it satisfy the CodeQL scan if we also added a _maxColors <= 16 check to that condition? That seems like a preferable fix to me, because it makes it clear what values we're actually dealing with here. Suggesting that _maxColors has a 64-bit range here is very misleading.

Copy link
Member Author

Choose a reason for hiding this comment

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

Unsure if CodeQL can detect a change like this but I do prefer your suggestion so lets give it a try

Comment on lines 436 to 438
// finalColumnInRow is 32-bit and currentIndex is 16-bit. If finalColumnInRow is higher
// than the 16-bit integer limit, we will loop indefinitely.
while (it && currentIndex <= saturated_cast<uint16_t>(finalColumnInRow))
Copy link
Member

Choose a reason for hiding this comment

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

I have not tested this, but looking at just the code, it seems to me that simply removing the narrow_cast above would have the same effect of fixing this bug.

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice catch. Seems like colorStarts is used below for _attr.replace() and it requires a size_type which is 32-bit, so seems that it'll work.

Copy link
Member Author

Choose a reason for hiding this comment

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

Looks like it was originally narrow casted to 16-bits so that it would work with x86 and x64, from looking at the error from the latest build. In x86 size_type is an unsigned short and in x64 it's an unsigned __int64.

I'll just convert finalColumnInRow to uint16_t when it's initialized and that should solve the issue.

Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

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

(I'll block for James and Leonard's comments)

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Jan 24, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot added the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Feb 1, 2025
@microsoft-github-policy-service microsoft-github-policy-service bot removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. labels Feb 19, 2025
@javierdlg javierdlg reopened this Feb 19, 2025
for (auto i = L'\0'; i < _translationTable.size(); i++)
for (size_t i = L'\0'; i < _translationTable.size(); i++)
Copy link
Collaborator

Choose a reason for hiding this comment

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

FYI, I don't think this change compiles. It might make more sense to cast the table size if that'll satisfy the CodeQL scan, i.e. something like this:

for (auto i = L'\0'; i < gsl::narrow_cast<wchar_t>(_translationTable.size()); i++)

There's no risk of an infinite loop here anyway because this code is executed at compile time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: To Cherry Pick
Development

Successfully merging this pull request may close these issues.

4 participants