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

AsmParser: parse source comment using scanner instead of regex #15209

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

clonker
Copy link
Member

@clonker clonker commented Jun 20, 2024

Fixes #15207
Fixes #13496

@clonker clonker marked this pull request as ready for review June 20, 2024 13:04
Copy link
Collaborator

@matheusaaguiar matheusaaguiar left a comment

Choose a reason for hiding this comment

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

Just some nitpicks and small suggestions.

libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
@matheusaaguiar
Copy link
Collaborator

matheusaaguiar commented Jun 20, 2024

Also, just to confirm/point to, I see that we have some tests in test/libyul/Parser.cpp which seems to cover parsing. Not sure if we need or would benefit from adding something more there.

@cameel cameel added refactor and removed refactor labels Jun 20, 2024
Copy link
Member

@cameel cameel left a comment

Choose a reason for hiding this comment

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

This needs a changelog entry for the bugfix.

Also note that github is a bit picky about the fixes/closes annotation. fixes issue #15207 did not work, The PR is not connected to the issue and won't close it automatically. You need Fixes #15207, i.e. without anything in between the word and the issue number.

Also, just to confirm/point to, I see that we have some tests in test/libyul/Parser.cpp which seems to cover parsing. Not sure if we need or would benefit from adding something more there.

The repro is a bit large and otherwise trivial, so I think it's ok to skip it.

I think we're missing some coverage for whitespace and newline handling behavior, because the PR passes all tests even though the way it handles whitespace seems to have changed.

libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
@clonker clonker force-pushed the asm_parser_use_scanner branch 2 times, most recently from 7cf8e50 to b3fd10e Compare June 21, 2024 16:21
Changelog.md Outdated Show resolved Hide resolved
liblangutil/Scanner.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Show resolved Hide resolved
liblangutil/Scanner.h Outdated Show resolved Hide resolved
@aarlt
Copy link
Member

aarlt commented Jun 25, 2024

I guess you could now also remove the rm ./*_bytecode_too_large_*.sol ./*_combined_too_large_*.sol in .circleci/parallel_bytecode_report.sh - if I remember correctly, the crashes where mainly happening because of the regexp stuff.

@cameel
Copy link
Member

cameel commented Jun 26, 2024

I guess you could now also remove the rm ./*_bytecode_too_large_*.sol ./*_combined_too_large_*.sol in .circleci/parallel_bytecode_report.sh - if I remember correctly, the crashes where mainly happening because of the regexp stuff.

Looks like it worked. Which is actually odd, because this PR doesn't fix #13496, does it? I mean, if it does then great, maybe we should close it too, but it's also possible that it got somehow fixed on develop and we didn't realize :)

@clonker
Copy link
Member Author

clonker commented Jun 27, 2024

I guess you could now also remove the rm ./*_bytecode_too_large_*.sol ./*_combined_too_large_*.sol in .circleci/parallel_bytecode_report.sh - if I remember correctly, the crashes where mainly happening because of the regexp stuff.

Looks like it worked. Which is actually odd, because this PR doesn't fix #13496, does it? I mean, if it does then great, maybe we should close it too, but it's also possible that it got somehow fixed on develop and we didn't realize :)

It does segfault for me in the issue you linked above on develop and not on this branch when, e.g., invoking solc --via-ir --asm test.sol. I assume it is because of the debug comments:

image

Invoking the same with --debug-info none does not segfault on develop, either.

@aarlt
Copy link
Member

aarlt commented Jun 27, 2024

I guess you could now also remove the rm ./*_bytecode_too_large_*.sol ./*_combined_too_large_*.sol in .circleci/parallel_bytecode_report.sh - if I remember correctly, the crashes where mainly happening because of the regexp stuff.

Looks like it worked. Which is actually odd, because this PR doesn't fix #13496, does it? I mean, if it does then great, maybe we should close it too, but it's also possible that it got somehow fixed on develop and we didn't realize :)

It does segfault for me in the issue you linked above on develop and not on this branch when, e.g., invoking solc --via-ir --asm test.sol. I assume it is because of the debug comments:

image

Invoking the same with --debug-info none does not segfault on develop, either.

yep exactly! its because of the debug comments. I ran into this when I was working on the debug attribute parsing stuff. I would say we should merge this soon so I can rework my PR.

@aarlt
Copy link
Member

aarlt commented Jun 27, 2024

In general it is a bug in std::regexp in some GCC versions that created that segfault.

Changelog.md Outdated Show resolved Hide resolved
…ed: Whitespace between the indices as well as single-quoted code snippets are now allowed.
Copy link
Member

@cameel cameel left a comment

Choose a reason for hiding this comment

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

I think we still need some some adjustments in the scanner and a few more tests. Other than that it looks pretty good now.

Comment on lines +837 to +838
if (c == '\\')
scanEscape();
Copy link
Member

Choose a reason for hiding this comment

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

If I understand this code correctly, this does not quite match the behavior of the original regex. The code here will just skip invalid escape sequences and stray \ at the end of input. If we want to match the original regex, we'd have to instead:

  • not interpret unrecognized escapes, just keep them as is,
  • report an unterminated string if we reach \ at the end of input (well, I guess reporting an illegal escape instead would be fine too, as long as it's still an error).

Copy link
Member Author

@clonker clonker Jun 28, 2024

Choose a reason for hiding this comment

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

Yeah it's true, it wasn't reflecting the RegEx behavior - although snippets are really just skipped during parsing, the important bit is the correct detection of the tail. That being said, it absolutely makes sense to interpret the 'special comment' literal string sensibly. Now everything that is escaped and interpretable is being interpreted as such and the rest is appended verbatim. I have added a couple tests to the scanner for that.

Copy link
Member

Choose a reason for hiding this comment

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

By the way, the most sensible behavior for such escapes would actually be to report an error, but that's breaking. They should never happen in Yul coming from the codegen and are only possible in user-supplied Yul, so maybe it's acceptable, buy I wouldn't do it in this PR. Maybe this is something that we should consider later though. Really, neither skipping them, nor keeping them "as is" is ideal.

libyul/AsmParser.cpp Outdated Show resolved Hide resolved
libyul/AsmParser.cpp Outdated Show resolved Hide resolved
test/libyul/Parser.cpp Outdated Show resolved Hide resolved
@cameel
Copy link
Member

cameel commented Jun 27, 2024

It does segfault for me in the issue you linked above on develop and not on this branch when, e.g., invoking solc --via-ir --asm test.sol. I assume it is because of the debug comments:

Ah, right. I focused on parsing the long hex string (which should not be affected by this PR) but overlooked the fact that such a string will also end up in a snippet as a part of debug info. In that case, yeah, this PR does fix it.

Copy link
Member

@cameel cameel left a comment

Choose a reason for hiding this comment

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

This generally looks good so I'm approving already.

I still have some final suggestions, mostly regarding wording and comments. The only bigger one would to change how unterminated escapes are handled, though that's not incorrect, just leaves some unexpected artifacts in the (invalid) literal.

@@ -3,6 +3,7 @@
Language Features:
* Accept declarations of state variables with ``transient`` data location (parser support only, no code generation yet).
* Make ``require(bool, Error)`` available when using the legacy pipeline.
* Yul: Parsing rules for source location comments have been relaxed: Whitespace between the indices as well as single-quoted code snippets are now allowed.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* Yul: Parsing rules for source location comments have been relaxed: Whitespace between the indices as well as single-quoted code snippets are now allowed.
* Yul: Parsing rules for source location comments have been relaxed: Whitespace between the location components as well as single-quoted code snippets are now allowed.

@@ -13,6 +14,7 @@ Compiler Features:


Bugfixes:
* AsmParser: Alleviates risk of encountering a segfault for very long comments.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* AsmParser: Alleviates risk of encountering a segfault for very long comments.
* Yul Parser: Fix segfault when parsing very long location comments.

Comment on lines +817 to +818
// the second source location is not parsed as such, as the hex string isn't interpreted as snippet but
// as the beginning of the tail in AsmParser
Copy link
Member

Choose a reason for hiding this comment

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

Looks like this comment was duplicated, even in tests that do not include the second source location at all :) It should probably have stayed only in the one test where it was relevant?

@@ -764,7 +764,7 @@ bool Scanner::scanEscape()
char c = m_char;

// Skip escaped newlines.
Copy link
Member

Choose a reason for hiding this comment

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

Outdated comment.

Suggested change
// Skip escaped newlines.
// Normally we ignore the slash just before a newline since it's meaningless.
// In the "special comment" mode, we preserve it though, like all invalid escapes.

Copy link
Member

@cameel cameel Jun 28, 2024

Choose a reason for hiding this comment

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

Also, one way to make this code more self-explanatory would be to add a meaningfully named parameter (e.g. _preserveInvalidEscapes or _rejectInvalidEscapes with the opposite meaning) instead of special-casing the SpecialComment mode here. It would make it clearer here why we're doing something different in this mode.

Then, at the point of call that would also make it more obvious that the function will behave differently:

		if (m_kind == ScannerKind::SpecialComment)
		{
			if (c == '\\')
				scanEscape(true /* _preserveInvalidEscapes */);

Comment on lines +862 to +863
if (c == '\\')
scanEscape();
Copy link
Member

Choose a reason for hiding this comment

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

It would be more consistent with the other branch to treat unterminated \ as IllegalEscapeSequence. Currently you continue, run scanEscape() and then error with IllegalStringEndQuote right after the loop.

It does work, but it's still weird to let scanEscape() run when we're at the end of input and m_char is 0, which I guess is assumed to never actually be read. The function will actually take that 0 and put into the literal and that literal is still accessible via currentLiteral() even when we error out.

Also, you should either handle the return value from scanEscape() or assert that it's not supposed to fail:

Suggested change
if (c == '\\')
scanEscape();
if (c == '\\')
{
if (isSourcePastEndOfInput())
return setError(ScannerError::IllegalEscapeSequence);
bool validEscape = scanEscape();
solAssert(validEscape);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants