Skip to content

Fix infinite loop with bad section ends in TastyHeaderUnpickler#25676

Open
SolalPirelli wants to merge 8 commits intoscala:mainfrom
dotty-staging:s/m9
Open

Fix infinite loop with bad section ends in TastyHeaderUnpickler#25676
SolalPirelli wants to merge 8 commits intoscala:mainfrom
dotty-staging:s/m9

Conversation

@SolalPirelli
Copy link
Copy Markdown
Contributor

Don't go backward with end of sections.

How much have you relied on LLM-based tools in this contribution?

not

How was the solution tested?

new test

val fileExperimental = readNat()
val toolingVersion = {
val length = readNat()
val length = readNonnegNat()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this one wasn't part of the original problem but seems like it needs fixing as well

@SolalPirelli SolalPirelli requested a review from mbovel April 1, 2026 13:33
mbovel
mbovel previously approved these changes Apr 1, 2026
else if (tag >= firstNatASTTreeTag) { readNat(); skipTree() }
else if (tag >= firstASTTreeTag) skipTree()
else if (tag >= firstNatTreeTag) readNat()
else if (tag >= firstNatTreeTag) readLongInt()
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

these two calls used to be equivalent because we didn't check that it was really a nat or really not a long

Copy link
Copy Markdown
Member

@sjrd sjrd left a comment

Choose a reason for hiding this comment

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

Details only.


/** Read a natural number fitting in a Long in big endian format, base 128.
* All but the last digits have bit 0x80 set.
/** Read a 63-bit natural (nonnegative) number in 2's complement big endian format, base 128, stored as octets.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
/** Read a 63-bit natural (nonnegative) number in 2's complement big endian format, base 128, stored as octets.
/** Read a 63-bit natural (nonnegative) number in big endian format, base 128, stored as octets.

It's not 2's complement if it's unsigned. And clearly the implementation does not manipulate the sign.

throw new UnpickleException(s"Expected a long nat, but read too many bytes (${bp - ogBp})")
}
if (x < 0) {
throw new UnpickleException(s"Expected a nat, got: $x")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since 9*7 = 63, we couldn't possibly have set the sign bit. Make it an assert rather than an UnpickleException?

UnpickleException = the input file is invalid ; AssertionError = whether or not the input file was valid, the unpickler had a bug.

Comment on lines +77 to +80
if (l < Int.MinValue || l > Int.MaxValue) {
throw new UnpickleException(s"Expected a 32-bit int, got: $l")
}
l.toInt
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
if (l < Int.MinValue || l > Int.MaxValue) {
throw new UnpickleException(s"Expected a 32-bit int, got: $l")
}
l.toInt
val i = l.toInt
if (i.toLong != l) {
throw new UnpickleException(s"Expected a 32-bit int, got: $l")
}
i

?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants