Bug 145298 - Arguments elimination phase mishandles arity check failure in its reduction of LoadVarargs to GetStack/PutStacks
Summary: Arguments elimination phase mishandles arity check failure in its reduction o...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Filip Pizlo
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2015-05-21 23:09 PDT by Filip Pizlo
Modified: 2015-05-22 11:48 PDT (History)
13 users (show)

See Also:


Attachments
the patch (10.43 KB, patch)
2015-05-21 23:11 PDT, Filip Pizlo
ggaren: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Filip Pizlo 2015-05-21 23:09:11 PDT
Patch forthcoming.
Comment 1 Filip Pizlo 2015-05-21 23:11:12 PDT
Created attachment 253578 [details]
the patch
Comment 2 Mark Lam 2015-05-22 09:50:22 PDT
<rdar://problem/21030149>
Comment 3 Mark Lam 2015-05-22 10:57:35 PDT
Comment on attachment 253578 [details]
the patch

View in context: https://bugs.webkit.org/attachment.cgi?id=253578&action=review

> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:501
> +                        DFG_ASSERT(m_graph, node, varargsData->limit - 1 >= varargsData->mandatoryMinimum);
> +                        unsigned limit = std::max(
> +                            varargsData->limit - 1, varargsData->mandatoryMinimum);

Is the following true?
1. varargs->limit means varargs->numberOfArgsPassedByCallerIncludingThis.
2. varargs->mandatoryMinimum means varargs->numberOfArgsRequiredByCallee.

> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:510
> +                            if (loadIndex + 1 < inlineCallFrame->arguments.size()) {

From reading the code, I see that inlineCallFrame->arguments.size is set to be the argumentsCountIncludingThis of the callee function to be inlined in ByteCodeParser::InlineStackEntry::InlineStackEntry().  Hence, I expect its indexes to range from 0 (for this) to N for the Nth argument.  How is it that you compare it to loadIndex + 1 here where loadIndex can have a varargsData->offset adjustment which comes from the caller?  

I’m sure I’m reading something wrong.  Can you explain what I’m misinterpreting here please?
Comment 4 Filip Pizlo 2015-05-22 11:19:04 PDT
(In reply to comment #3)
> Comment on attachment 253578 [details]
> the patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=253578&action=review
> 
> > Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:501
> > +                        DFG_ASSERT(m_graph, node, varargsData->limit - 1 >= varargsData->mandatoryMinimum);
> > +                        unsigned limit = std::max(
> > +                            varargsData->limit - 1, varargsData->mandatoryMinimum);
> 
> Is the following true?
> 1. varargs->limit means varargs->numberOfArgsPassedByCallerIncludingThis.

No.

> 2. varargs->mandatoryMinimum means varargs->numberOfArgsRequiredByCallee.

Yes.

> 
> > Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:510
> > +                            if (loadIndex + 1 < inlineCallFrame->arguments.size()) {
> 
> From reading the code, I see that inlineCallFrame->arguments.size is set to
> be the argumentsCountIncludingThis of the callee function to be inlined in
> ByteCodeParser::InlineStackEntry::InlineStackEntry().  Hence, I expect its
> indexes to range from 0 (for this) to N for the Nth argument.  How is it
> that you compare it to loadIndex + 1 here where loadIndex can have a
> varargsData->offset adjustment which comes from the caller?  

This entire code is guarded by:

                    if (inlineCallFrame
                        && !inlineCallFrame->isVarargs()
                        && inlineCallFrame->arguments.size() - varargsData->offset <= varargsData->limit) {

We use loadIndex + 1 because loadIndex is an argumentIndex rather than an argumentIndexIncludingThis.

> 
> I’m sure I’m reading something wrong.  Can you explain what I’m
> misinterpreting here please?
Comment 5 Geoffrey Garen 2015-05-22 11:23:08 PDT
Comment on attachment 253578 [details]
the patch

View in context: https://bugs.webkit.org/attachment.cgi?id=253578&action=review

>> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:501
>> +                            varargsData->limit - 1, varargsData->mandatoryMinimum);
> 
> Is the following true?
> 1. varargs->limit means varargs->numberOfArgsPassedByCallerIncludingThis.
> 2. varargs->mandatoryMinimum means varargs->numberOfArgsRequiredByCallee.

unsigned mandatoryMinimum; // The number of elements on the stack that must be initialized; if the array is too short then the missing elements must get undefined. Does not include "this".
    unsigned limit; // Maximum number of elements to load. Includes "this".
Comment 6 Geoffrey Garen 2015-05-22 11:27:03 PDT
Comment on attachment 253578 [details]
the patch

View in context: https://bugs.webkit.org/attachment.cgi?id=253578&action=review

r=me

> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:521
> +                                if (storeIndex >= varargsData->mandatoryMinimum) {

I'm curious: When does this case happen, and does it happen in the attached test case? If not, it's probably worth adding a test case for this.
Comment 7 Filip Pizlo 2015-05-22 11:33:02 PDT
(In reply to comment #6)
> Comment on attachment 253578 [details]
> the patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=253578&action=review
> 
> r=me
> 
> > Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:521
> > +                                if (storeIndex >= varargsData->mandatoryMinimum) {
> 
> I'm curious: When does this case happen, and does it happen in the attached
> test case? If not, it's probably worth adding a test case for this.

This will trigger it:

function foo() { // mandatoryMinimum = 0, since foo->numParameters() = 0
}

function bar() {
    foo.apply(this, arguments); // the arguments object here is statically known to have 3 entries, when we inline this into baz.  In this case, limit will be 4.
}

function baz() {
    bar(1, 2, 3);
}

I'll add a test.
Comment 8 Filip Pizlo 2015-05-22 11:33:19 PDT
Comment on attachment 253578 [details]
the patch

View in context: https://bugs.webkit.org/attachment.cgi?id=253578&action=review

> Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp:500
> +                        DFG_ASSERT(m_graph, node, varargsData->limit - 1 >= varargsData->mandatoryMinimum);
> +                        unsigned limit = std::max(

I guess I shouldn't use max here, and just use limit - 1 directly, since the above is a release assert.
Comment 9 Filip Pizlo 2015-05-22 11:48:48 PDT
Landed in http://trac.webkit.org/changeset/184781