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

[FLINK-15266] Fix NPE for case operator code gen in blink planner #10594

Merged

Conversation

libenchao
Copy link
Member

What is the purpose of the change

This pr fixes the NPE bug in blink case operator code gen as described in FLINK-15266.

Brief change log

For case operator result type, generate primitive type only when trueAction and falseAction both return non-null types.

Verifying this change

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): (no)
  • The public API, i.e., is any changed class annotated with @Public(Evolving): (no)
  • The serializers: (no)
  • The runtime per-record code paths (performance sensitive): (yes)
  • Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Yarn/Mesos, ZooKeeper: (no)
  • The S3 file system connector: (no)

Documentation

  • Does this pull request introduce a new feature? (no)

@flinkbot
Copy link
Collaborator

Thanks a lot for your contribution to the Apache Flink project. I'm the @flinkbot. I help the community
to review your pull request. We will use this comment to track the progress of the review.

Automated Checks

Last check on commit 2c31b9b (Mon Dec 16 13:03:48 UTC 2019)

Warnings:

  • No documentation files were touched! Remember to keep the Flink docs up to date!

Mention the bot in a comment to re-run the automated checks.

Review Progress

  • ❓ 1. The [description] looks good.
  • ❓ 2. There is [consensus] that the contribution should go into to Flink.
  • ❓ 3. Needs [attention] from.
  • ❓ 4. The change fits into the overall [architecture].
  • ❓ 5. Overall code [quality] is good.

Please see the Pull Request Review Guide for a full explanation of the review process.


The Bot is tracking the review progress through labels. Labels are applied according to the order of the review items. For consensus, approval by a Flink committer of PMC member is required Bot commands
The @flinkbot bot supports the following commands:

  • @flinkbot approve description to approve one or more aspects (aspects: description, consensus, architecture and quality)
  • @flinkbot approve all to approve all aspects
  • @flinkbot approve-until architecture to approve everything until architecture
  • @flinkbot attention @username1 [@username2 ..] to require somebody's attention
  • @flinkbot disapprove architecture to remove an approval you gave earlier

@flinkbot
Copy link
Collaborator

flinkbot commented Dec 16, 2019

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run travis re-run the last Travis build
  • @flinkbot run azure re-run the last Azure build

Copy link
Contributor

@KurtYoung KurtYoung left a comment

Choose a reason for hiding this comment

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

Thanks for fixing this! Could you also add a test case?

@KurtYoung
Copy link
Contributor

Please fix the code style error as well.

@KurtYoung KurtYoung self-assigned this Dec 17, 2019
@wuchong
Copy link
Member

wuchong commented Dec 19, 2019

Hi @libenchao , do you have time to add some tests for this?

As this is a blocker issue of release 1.10, if you don't have enough time, I can help to improve the fixing.

@libenchao
Copy link
Member Author

@KurtYoung @wuchong Thanks for the review. Sorry for the late reply.

About the tests, I've been working around. I'd appreciate it if you could give some advice here. I come out with two testing methods:

  1. Just add a ITCaseTest to cover this scenario, like select case when 0 < EXPR$0 then cast(EXPR$1 as bigint) else 0 end from (values (1, ''), (2, '12')).
  2. Like other code gen testings, build a GeneratedClass, get it's instance, invoke it's method, verify the result.

@JingsongLi
Copy link
Contributor

Hi @libenchao , thanks for fixing, I'll review this.

@JingsongLi
Copy link
Contributor

JingsongLi commented Dec 19, 2019

About the tests:
1.If possible, please add test in ScalarOperatorsTest. This is the first choice.
2.If it is hard to add test in expression tests, should add test in CalcITCase.

This case, I think you can try # 1 first.

@@ -1278,7 +1278,11 @@ object ScalarOperatorGens {
val falseAction = generateIfElse(ctx, operands, resultType, i + 2)

val Seq(resultTerm, nullTerm) = newNames("result", "isNull")
val resultTypeTerm = primitiveTypeTermForType(resultType)
val resultTypeTerm = if (trueAction.resultType.isNullable || falseAction.resultType.isNullable) {
boxedTypeTermForType(resultType)
Copy link
Contributor

Choose a reason for hiding this comment

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

You should not modify here. We always use primitiveTypeTermForType as much as possible.

boxedTypeTermForType(resultType)
} else {
primitiveTypeTermForType(resultType)
}

val operatorCode = if (ctx.nullCheck) {
s"""
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the reason is here, should first check nullTerm, if it is true, should not assign resultTerm.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the review. The result for NPE is that we assign null to a primitive type variable here, if we not assign resultTerm when nullTerm is true, then resultTerm will not be null at last. IMHO, this should be null for resultTerm.

Or we can make ${trueAction.resultTerm} be the resultTerm for the returned GeneratedExpression ?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ignore my above comment...
I've got your point, and will update the code very soon.

@@ -1287,12 +1287,16 @@ object ScalarOperatorGens {
|boolean $nullTerm;
|if (${condition.resultTerm}) {
| ${trueAction.code}
| $resultTerm = ${trueAction.resultTerm};
| if (!${trueAction.nullTerm}) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This will lead to a risk, if trueAction.nullTerm is a expression instead of a variable, maybe will some problem, so I suggest you:

$nullTerm = ${trueAction.nullTerm};
if (!$nullTerm) {
  $resultTerm = ${trueAction.resultTerm};
}

At least, we can ensure nullTerm is just a variable.

Copy link
Member Author

Choose a reason for hiding this comment

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

sure, thanks for the suggestion.
code updated.

Copy link
Member Author

Choose a reason for hiding this comment

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

BTW, I encountered below error running ScalarOperatorsTest after updating the code:

java.lang.VerifyError: Expecting a stackmap frame at branch target 32
Exception Details:
  Location:
    TestFunction$163.map(Ljava/lang/Object;)Ljava/lang/Object; @19: ifne
  Reason:
    Expected stackmap frame at this location.
  Bytecode:
    0x0000000: 2bc0 000e 4d2c 100d b900 1402 0036 0401
    0x0000010: 4e15 049a 000d 2c10 0d05 b900 1803 004e
    0x0000020: 2d3a 4415 049a 000e 2ab4 001c 1944 b600
    0x0000030: 223a 442c 05b9 0014 0200 3632 0236 3115
......

It seems to be a bug in Janino. After I searched Janino's issues, I found this janino-compiler/janino#90 (comment)

Have you ever met the same problem?

Copy link
Contributor

Choose a reason for hiding this comment

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

Never encounter... But maybe because our code generate code has some problem, we can run again after fixing.

Choose a reason for hiding this comment

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

@libenchao @JingsongLi

Hello! This might be a bit unrelated, but I am developing on flink and I am also running into a very similar VerifyError pointing to a Janino code generated method (specifically in the Flink protobuf row serialization codepath). How did you workaround/resolve this issue?

Copy link
Member Author

Choose a reason for hiding this comment

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

@kurnoolsaketh We didn't solve it, it just disappeared.

Choose a reason for hiding this comment

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

interesting.. thanks for the info.

| $nullTerm = ${trueAction.nullTerm};
| if (!$nullTerm) {
| $resultTerm = ${trueAction.resultTerm};
Copy link
Contributor

Choose a reason for hiding this comment

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

You need assign resultTerm to a default value too.
val defaultValue = primitiveDefaultValue(resultType)

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks for the reminder. done.

Copy link
Contributor

@JingsongLi JingsongLi left a comment

Choose a reason for hiding this comment

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

LGTM after travis passing.

@libenchao
Copy link
Member Author

@flinkbot run travis

Copy link
Member

@wuchong wuchong left a comment

Choose a reason for hiding this comment

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

Thanks for the fixing @libenchao and thanks for the reviewing @JingsongLi .

Looks good to me too.

Will merge it.

@wuchong wuchong merged commit 5f86f2d into apache:master Dec 20, 2019
wuchong pushed a commit that referenced this pull request Dec 20, 2019
wuchong pushed a commit that referenced this pull request Dec 20, 2019
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.

7 participants