Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix($parse): treat falsy values as defined in assignment expressions #14994

Closed
wants to merge 1 commit into from

Conversation

m-amr
Copy link
Contributor

@m-amr m-amr commented Aug 6, 2016

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
bug, solving Issue #14990

Closes #14990

@m-amr m-amr force-pushed the fix_parse_falsy_value branch from e3b5ab8 to 45674dc Compare August 6, 2016 00:20
@@ -1274,6 +1274,10 @@ ASTCompiler.prototype = {
return '!(' + expression + ')';
},

null: function(expression) {
Copy link
Contributor

@lgalfaso lgalfaso Aug 6, 2016

Choose a reason for hiding this comment

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

Please rename to isNull

@lgalfaso
Copy link
Contributor

lgalfaso commented Aug 6, 2016

Looks like variations of the same issue are present at
https://github.com/angular/angular.js/blob/master/src/ng/parse.js#L1069
and
https://github.com/angular/angular.js/blob/master/src/ng/parse.js#L1080

with the expressions foo.bar.baz = 1 and foo.bar['baz'] = 1 where in both cases foo = {bar: ''}

It would be best to fix the three cases in one go.

@m-amr
Copy link
Contributor Author

m-amr commented Aug 6, 2016

@lgalfaso
Thanks for your feedback

I have a problem with the unit test.

 it('should not assign a property to locals properties with falsy value', inject(function($parse) {
      var local = {a:0};
      expect(function() {
        $parse("a.b =1")(local);
      }).toThrow();
  });

I get this error 'Expected function to throw an exception'
but when i call $parse("a.b =1")(local) alone i get
TypeError: Cannot create property 'b' on number '0'

I have no idea why toThrow() doesn't detect that TypeError was thrown from parse function ?

@lgalfaso
Copy link
Contributor

lgalfaso commented Aug 6, 2016

There are at least 2 parts:

The CSP: true version also needs to be fixed, these are
https://github.com/angular/angular.js/blob/master/src/ng/parse.js#L1706
https://github.com/angular/angular.js/blob/master/src/ng/parse.js#L1731
https://github.com/angular/angular.js/blob/master/src/ng/parse.js#L1750

There might be discrepancies on how this is handled in different browsers.

@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 45674dc to d44c539 Compare August 6, 2016 14:31
@m-amr
Copy link
Contributor Author

m-amr commented Aug 6, 2016

@lgalfaso
After the fix that i had done.
Here are the results of the three cases
Case 1:

    $scope.a = 0;
    $scope.$eval("a.b=2");

I get TypeError: Cannot create property 'b' on number '0'

Case 2:

    $scope.a = 0;
    $scope.$eval("a['b']=2");

I get TypeError: Cannot create property 'b' on number '0'

Case 3:

    $scope.a = 0;
    $scope.$eval("a={'b':2}");

This shouldn't throw any error because assigning 'a' with another value.

Is that what you mean ?

@lgalfaso
Copy link
Contributor

lgalfaso commented Aug 6, 2016

For some reasons that are not important, the following 3 expressions follow 3 slightly different code paths

foo.bar = 1;
foo.bar.baz = 1;
foo.bar['baz'] = 1;

In this case we want to fix the three of them as they all have the same issue. This is, the following cases should behave in the same way

$parse('foo.bar = 1')({foo: 0});
$parse('foo.bar.baz = 1')({foo: {bar: 0}});
$parse('foo.bar["baz"] = 1')({foo: {bar: 0}});

@m-amr m-amr force-pushed the fix_parse_falsy_value branch from d44c539 to 677dd3d Compare August 8, 2016 15:32
@m-amr
Copy link
Contributor Author

m-amr commented Aug 8, 2016

After I handled these two cases

  $parse('foo.bar.baz = 1')({foo: {bar: 0}});
  $parse('foo.bar["baz"] = 1')({foo: {bar: 0}});

Some old cases failed

     it('should prevent assigning only in the context of an actual constructor', function() {
      // foo.constructor is not a constructor.
      expect(function() {
        delete scope.foo;
        scope.$eval('foo.constructor[0] = ""', {foo: {constructor: ''}});
      }).not.toThrow();

and

   it('should prevent assigning only in the context of an actual prototype', function() {
      // foo.constructor.prototype is not a constructor prototype.
      expect(function() {
        delete scope.foo;
        scope.$eval('foo.constructor.prototype[0] = ""', {foo: {constructor: {prototype: ''}}});
      }).not.toThrow();

So these Cases are against the the change to handle

    $parse('foo.bar.baz = 1')({foo: {bar: 0}});
    $parse('foo.bar["baz"] = 1')({foo: {bar: 0}});

so what is your suggestion ?

@@ -3900,6 +3900,34 @@ describe('parser', function() {
expect(isFunction(s.toString)).toBe(true);
expect(l.toString).toBe(1);
}));

it('should assign a property to locals properties with null or undefined value', inject(function($parse) {
Copy link
Member

Choose a reason for hiding this comment

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

The description is misleading. There is no locals object in the test. Use scope instead.

@gkalpak
Copy link
Member

gkalpak commented Aug 8, 2016

The tests you mentioned were affected by the bug you fixed. You could change the initial values to something that can be assigned to, e.g.:

// Before:
{foo: {constructor: ''}}
{foo: {constructor: {prototype: ''}}}

// After:
{foo: {constructor: {}}}
{foo: {constructor: {prototype: {}}}}

@m-amr
Copy link
Contributor Author

m-amr commented Aug 10, 2016

@gkalpak
Could you please check this.
I have no idea why at the Unit test the toThrow function didn't detect any exception throw from parse function
when I write

      var scope = {a:0};
      $parse("a.b =1")(scope);

I get this error.
TypeError: Cannot create property 'b' on number '0'
at fn (eval at compile (/Apache Server Root/repositories/angular.js/src/ng/parse.js:906:15), :4:248)
at Object. (/Apache Server Root/repositories/angular.js/test/ng/parseSpec.js:3916:27)
at Object.invoke (/Apache Server Root/repositories/angular.js/src/auto/injector.js:879:19)
at Object.workFn (/Apache Server Root/repositories/angular.js/src/ngMock/angular-mocks.js:3103:20)
Error: Declaration Location
at window.inject.angular.mock.inject (/Apache Server Root/repositories/angular.js/src/ngMock/angular-mocks.js:3065:25)
at Suite. (/Apache Server Root/repositories/angular.js/test/ng/parseSpec.js:3914:81)
at Suite. (/Apache Server Root/repositories/angular.js/test/ng/parseSpec.js:3867:7)
at /Apache Server Root/repositories/angular.js/test/ng/parseSpec.js:1838:5
Chrome 52.0.2743 (Mac OS X 10.11.5): Executed 5535 of 5535 (2 FAILED) (22.486 secs / 21.484 secs)

but when i use

      var scope = {a:0};
      expect(function() {
        $parse("a.b =1")(scope);
      }).toThrow();

I get
Chrome 52.0.2743 (Mac OS X 10.11.5) parser csp: true locals should not assign a property to scope properties with falsy value FAILED
Expected function to throw an exception.
at Object. (/Apache Server Root/repositories/angular.js/test/ng/parseSpec.js:3919:14)
at Object.invoke (/Apache Server Root/repositories/angular.js/src/auto/injector.js:879:19)
at Object.workFn (/Apache Server Root/repositories/angular.js/src/ngMock/angular-mocks.js:3103:20)

I have no Idea why the test didn't detect the thrown exception, but when i used
$parse("a.b =1")(scope); it throw exception.

Does angular handle these exception in a different way ? or I am missing something.

@m-amr m-amr force-pushed the fix_parse_falsy_value branch 2 times, most recently from 7060488 to bf9cbef Compare August 11, 2016 20:09
@gkalpak
Copy link
Member

gkalpak commented Aug 12, 2016

@m-amr, I see you pushed another commit. Were you able to solve the issue you had or should I take a look?

@m-amr
Copy link
Contributor Author

m-amr commented Aug 12, 2016

@gkalpak, No I still have the same problem, Could you please check it.

@m-amr m-amr closed this Aug 12, 2016
@m-amr m-amr reopened this Aug 12, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from bf9cbef to 2493520 Compare September 9, 2016 20:29
m-amr added a commit to m-amr/angular.js that referenced this pull request Sep 9, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 2493520 to 4a2c3f2 Compare September 10, 2016 00:21
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 10, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from bab639c to 21e225a Compare October 10, 2016 21:17
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 10, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 21e225a to d6beae8 Compare October 10, 2016 21:27
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 10, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from d6beae8 to 0cb3cb2 Compare October 10, 2016 21:54
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 10, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 0cb3cb2 to 36ddd18 Compare October 10, 2016 22:01
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 10, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 36ddd18 to 497281e Compare October 10, 2016 22:03
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 10, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 497281e to 4102e33 Compare October 10, 2016 22:22
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 10, 2016
@m-amr
Copy link
Contributor Author

m-amr commented Oct 10, 2016

@gkalpak
Thanks for your feedback,
I had added all the test cases that you had mentioned and every thing work,
Could you please give it a last look ?

@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 4102e33 to 14eaaf2 Compare October 11, 2016 03:53
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 11, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 14eaaf2 to afc91f4 Compare October 11, 2016 03:54
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 11, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from afc91f4 to 2e78764 Compare October 11, 2016 04:11
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 11, 2016
function tryParseAndIgnoreException(expression) {
try {
$parse(expression)(scope);
} catch (error) {/** ignore exception*/}
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Use /* ... */ (and consistent whitespace).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@gkalpak
Copy link
Member

gkalpak commented Oct 11, 2016

LGTM
I'll let @lgalfaso sign it off 😃

@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 2e78764 to 859ab01 Compare October 11, 2016 22:40
m-amr added a commit to m-amr/angular.js that referenced this pull request Oct 11, 2016
@m-amr m-amr force-pushed the fix_parse_falsy_value branch from 859ab01 to d3cffcf Compare October 11, 2016 22:41
@lgalfaso
Copy link
Contributor

LGTM
landed as 4f44e01

@lgalfaso lgalfaso closed this Oct 12, 2016
ellimist pushed a commit to ellimist/angular.js that referenced this pull request Mar 15, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

fix($parse): treat falsy values as defined in assignment expressions
5 participants