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

[Ruby] Message.decode/encode: Add max_recursion_depth option #9218

Merged

Conversation

lfittl
Copy link
Contributor

@lfittl lfittl commented Nov 13, 2021

This allows increasing the recursing depth from the default of 64, by
setting the "max_recursion_depth" to the desired integer value. This is
useful to encode or decode complex nested protobuf messages that otherwise
error out with a RuntimeError or "Error occurred during parsing".

Fixes #1493

@google-cla google-cla bot added the cla: yes label Nov 13, 2021
lfittl added a commit to pganalyze/pg_query that referenced this pull request Nov 13, 2021
Depends on protocolbuffers/protobuf#9218, until
that is merged this can only be used with a custom built protobuf gem.

Fixes #209
lfittl added a commit to pganalyze/pg_query that referenced this pull request Nov 13, 2021
Depends on protocolbuffers/protobuf#9218, until
that is merged this can only be used with a custom built protobuf gem.

Fixes #209
lfittl added a commit to pganalyze/pg_query that referenced this pull request Nov 13, 2021
Depends on protocolbuffers/protobuf#9218, until
that is merged this can only be used with a custom built protobuf gem.

Fixes #209
@lfittl lfittl force-pushed the issue-1493-add-decode-depth-option branch from c1d3b1b to fab7498 Compare November 14, 2021 16:59
@lfittl lfittl changed the title [Ruby] Message.decode: Add max_recursion_depth option [Ruby] Message.decode/encode: Add max_recursion_depth option Nov 14, 2021
@elharo elharo requested a review from haberman November 15, 2021 14:52
VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("max_recursion_depth")));

if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
options = FIX2INT(depth) << 16;
Copy link
Member

Choose a reason for hiding this comment

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

Please use UPB_DECODE_MAXDEPTH(). And we should also avoid overwriting the options completely, eg.

  options |= UPB_DECODE_MAXDEPTH(FIX2INT(depth));

VALUE depth = rb_hash_lookup(hash_args, ID2SYM(rb_intern("max_recursion_depth")));

if (depth != Qnil && TYPE(depth) == T_FIXNUM) {
options = FIX2INT(depth) << 16;
Copy link
Member

Choose a reason for hiding this comment

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

Ditto here.

@haberman
Copy link
Member

Looks like we need this implemented on the JRuby side too.

@lfittl
Copy link
Contributor Author

lfittl commented Nov 26, 2021

@haberman Thanks for the review - addressed in the latest commit.

protected DynamicMessage build(ThreadContext context, int depth) {
if (depth > SINK_MAXIMUM_NESTING) {
protected DynamicMessage build(ThreadContext context, int depth, int maxRecursionDepth) {
if (depth >= maxRecursionDepth) {
Copy link
Contributor Author

@lfittl lfittl Nov 26, 2021

Choose a reason for hiding this comment

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

Note this is changed to match the UPB library behavior (> => >=), and SINK_MAXIMUM_NESTING is incremented by one accordingly.

@lfittl
Copy link
Contributor Author

lfittl commented Dec 7, 2021

@haberman I wanted to check if you could re-trigger a test build so we can confirm that the issues are now fixed? Thanks!

This allows increasing the recursing depth from the default of 64, by
setting the "max_recursion_depth" to the desired integer value. This is
useful to encode or decode complex nested protobuf messages that otherwise
error out with a RuntimeError or "Error occurred during parsing".

Fixes protocolbuffers#1493
@lfittl lfittl force-pushed the issue-1493-add-decode-depth-option branch from 51433c5 to 29909eb Compare December 9, 2021 02:47
@lfittl
Copy link
Contributor Author

lfittl commented Dec 9, 2021

@acozzette Thanks for the re-run - I can't really explain the test failure, it does not seem related to the actual code change. I've just rebased onto the latest main, in case that fixes the errors.

Could you re-run once more? Thank you!

@acozzette
Copy link
Member

@lfittl I noticed that some of our Ruby tests started failing a few days ago, though I have not had a chance to investigate yet. It could well be that the test failure is unrelated.

@lfittl
Copy link
Contributor Author

lfittl commented Dec 9, 2021

@lfittl I noticed that some of our Ruby tests started failing a few days ago, though I have not had a chance to investigate yet. It could well be that the test failure is unrelated.

Yeah, looks like the release tests are still failing (as they are on #9291), but otherwise this is green now (looks like the rebase fixed the other tests).

@haberman Let me know if you'd like to see any other adjustments. Thanks for reviewing!

@lfittl
Copy link
Contributor Author

lfittl commented Jan 7, 2022

@haberman Happy New Year! - let me know if you'd like to see anything else adjusted on this PR :)

@acozzette
Copy link
Member

I tried to resolve the merge conflicts in the GitHub UI just now. Hopefully that will work and then I will merge this unless @haberman has other comments.

@haberman
Copy link
Member

haberman commented Feb 3, 2022

I think the only remaining issue is making sure we are being as consistent as possible with other languages:

I just checked and Java, C++, and appears to calls this "recursion limit" instead of "max recursion depth:

/// <summary>
/// Returns the recursion limit for this stream. This limit is applied whilst reading messages,
/// to avoid maliciously-recursive data.
/// </summary>
/// <remarks>
/// The default limit is 100.
/// </remarks>
/// <value>
/// The recursion limit for this stream.
/// </value>
public int RecursionLimit { get { return state.recursionLimit; } }

// Sets the maximum recursion depth. The default is 100.
void SetRecursionLimit(int limit);

/**
* Set the maximum message recursion depth. In order to prevent malicious messages from causing
* stack overflows, {@code CodedInputStream} limits how deeply messages may be nested. The default
* limit is 100.
*
* @return the old limit.
*/
public final int setRecursionLimit(final int limit) {
if (limit < 0) {
throw new IllegalArgumentException("Recursion limit cannot be negative: " + limit);
}
final int oldLimit = recursionLimit;
recursionLimit = limit;
return oldLimit;
}

In that case, could we call the parameter recursion_limit instead of max_recursion_depth?

Sorry for the delay!

@acozzette
Copy link
Member

Let me go ahead and merge this, and I will send out a follow-up pull request to rename the parameter to recursion_limit. Thanks, @lfittl!

@acozzette acozzette merged commit fbe6ab2 into protocolbuffers:master Feb 9, 2022
@lfittl
Copy link
Contributor Author

lfittl commented Feb 9, 2022

@acozzette @haberman Excellent, thanks for the help & merging this :)

@lfittl lfittl deleted the issue-1493-add-decode-depth-option branch February 9, 2022 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ruby] More flexible ENCODE_MAX_NESTING
5 participants