RESOLVED FIXED 32012
JavaScript delete operator returns true for string properties
https://bugs.webkit.org/show_bug.cgi?id=32012
Summary JavaScript delete operator returns true for string properties
Kent Hansen
Reported 2009-12-01 00:52:59 PST
According to the ECMAScript 5 specification section 15.5.5.2, string properties whose names are valid string indices are not configurable, hence the delete operator should return false when applied to such a property.
Attachments
Proposed patch and test (3.73 KB, patch)
2009-12-01 02:57 PST, Kent Hansen
darin: review-
Revised patch with more test cases and using toArrayIndex() when converting identifier to string index (6.38 KB, patch)
2009-12-02 09:43 PST, Kent Hansen
darin: review-
Revised patch (back to basics) and more test cases (4.23 KB, patch)
2009-12-03 02:22 PST, Kent Hansen
no flags
Kent Hansen
Comment 1 2009-12-01 02:57:46 PST
Created attachment 44062 [details] Proposed patch and test
WebKit Review Bot
Comment 2 2009-12-01 03:00:07 PST
style-queue ran check-webkit-style on attachment 44062 [details] without any errors.
Darin Adler
Comment 3 2009-12-01 11:26:49 PST
Comment on attachment 44062 [details] Proposed patch and test Thanks for tackling this! This is almost right, but not quite. > + bool isStrictUInt32; > + unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); > + if (isStrictUInt32 && internalValue()->canGetIndex(i)) > + return false; This code needs to use toArrayIndex rather than toStrictUInt32. These functions differ in how they handle the value 4294967295. And you should make sure there is a test case for that particular number and other numbers just higher and lower than that. review-
Kent Hansen
Comment 4 2009-12-02 09:43:38 PST
Created attachment 44159 [details] Revised patch with more test cases and using toArrayIndex() when converting identifier to string index
Kent Hansen
Comment 5 2009-12-02 09:48:29 PST
(In reply to comment #3) > (From update of attachment 44062 [details]) > Thanks for tackling this! This is almost right, but not quite. > > > + bool isStrictUInt32; > > + unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); > > + if (isStrictUInt32 && internalValue()->canGetIndex(i)) > > + return false; > > This code needs to use toArrayIndex rather than toStrictUInt32. These functions > differ in how they handle the value 4294967295. And you should make sure there > is a test case for that particular number and other numbers just higher and > lower than that. > > review- Hi Darin, thanks! I was using the same approach as used elsewhere in JSString to calculate the index. I've revised the patch and refactored the code to always use the same conversion method (in getOwnPropertyDescriptor() and getOwnPropertySlot()) too). Let me know if you think it's worth it to do the refactoring in a separate commit and then add the deleteProperty()-specific stuff after that one.
WebKit Review Bot
Comment 6 2009-12-02 09:48:55 PST
Attachment 44159 [details] did not pass style-queue: Failed to run "WebKitTools/Scripts/check-webkit-style" exit_code: 1 JavaScriptCore/runtime/JSString.h:173: Code inside a namespace should not be indented. [whitespace/indent] [4] Total errors found: 1
Darin Adler
Comment 7 2009-12-02 09:59:17 PST
Comment on attachment 44159 [details] Revised patch with more test cases and using toArrayIndex() when converting identifier to string index > + unsigned toIndex(const Identifier& propertyName, bool *ok); WebKit coding style requires putting the "*" next to the "bool", not the "ok". > + inline unsigned JSString::toIndex(const Identifier& propertyName, bool *ok) > + { > + unsigned i = propertyName.toArrayIndex(ok); > + *ok = *ok && canGetIndex(i); > + return i; > + } I think it's slightly strange to include the canGetIndex call inside a function named toIndex. That's inconsistent with other functions named toIndex, and so perhaps the function should have a different name. But since I don't have another to suggest, we can probably live with this. I would probably call the output variable something more like isIndex rather than ok given the slightly broader purpose of the function. > + (void)internalValue()->toIndex(propertyName, &isIndex); WebKit code does not use this style, with explicit casts to (void) when ignoring function results. > +description("This page tests deletion of properties on a string object."); > + > +var str = "abc"; > +shouldBe('str.length', '3'); > +shouldBe('delete str.length', 'false'); > +shouldBe('delete str[0]', 'false'); > +shouldBe('delete str[1]', 'false'); > +shouldBe('delete str[2]', 'false'); > +shouldBe('delete str[3]', 'true'); > +shouldBe('delete str[-1]', 'true'); > +shouldBe('delete str[4294967294]', 'true'); > +shouldBe('delete str[4294967295]', 'true'); > +shouldBe('delete str.foo', 'true'); Looking at the test and test results I now realize that there is no detectable behavior change from what I asked you to do in the last patch, since indices that are beyond of the length of the string are treated no differently from identifiers that are not valid indices. Thus the special value that is a UInt32 but not a valid index doesn't actually need special handling. That means that using toStrictUInt32 was already acceptable and even slightly more efficient. Using toIndex, while more logical, adds an unnecessary additional check for that special value. Ideally I would like to see a test that includes 4294967296 as well, and also test cases for floating pointer numbers such as "0.0" and "0.1" to make sure that "0.0" correctly deletes the zero element and "0.1" correctly does not. I think the patch is fine as is, but I'm going to say review- because of the two minor style issues that check-webkit-style will no doubt catch as well. You could also consider my comments. Sorry for giving you conflicting advice.
Kent Hansen
Comment 8 2009-12-03 02:22:49 PST
Created attachment 44220 [details] Revised patch (back to basics) and more test cases
WebKit Review Bot
Comment 9 2009-12-03 02:25:48 PST
style-queue ran check-webkit-style on attachment 44220 [details] without any errors.
Kent Hansen
Comment 10 2009-12-03 02:34:54 PST
(In reply to comment #7) > Looking at the test and test results I now realize that there is no detectable > behavior change from what I asked you to do in the last patch, since indices > that are beyond of the length of the string are treated no differently from > identifiers that are not valid indices. Thus the special value that is a UInt32 > but not a valid index doesn't actually need special handling. That means that > using toStrictUInt32 was already acceptable and even slightly more efficient. > Using toIndex, while more logical, adds an unnecessary additional check for > that special value. Right. Looking at the ECMA algorithm, using toStrictUInt32 should be sufficient; there isn't any side-effects even if we incorrectly fall through the initial "is array index" test when the input is 4294967295 since, as you noted, the subsequent bounds check will catch it. I've reverted back to the initial patch. It irks me a bit that the "isStrictUInt32 and index is in range" check is done in three places now, but I'll leave any attempts at refactoring out of this patch. (By the way, the style checker only reported "code inside namespace should not be indented", which I disregarded since the rest of the functions in JSString.h are indented.) > > Ideally I would like to see a test that includes 4294967296 as well, and also > test cases for floating pointer numbers such as "0.0" and "0.1" to make sure > that "0.0" correctly deletes the zero element and "0.1" correctly does not. I've added these, and also a test for '0.0' (to make sure it's not treated as an array index).
Kent Hansen
Comment 11 2009-12-03 02:42:34 PST
(In reply to comment #10) > I've reverted back to the initial patch. It irks me a bit that the > "isStrictUInt32 and index is in range" check is done in three places now, but > I'll leave any attempts at refactoring out of this patch. (By the way, the > style checker only reported "code inside namespace should not be indented", > which I disregarded since the rest of the functions in JSString.h are > indented.) Actually, I created a patch where deleteProperty() calls getOwnPropertyDescriptor(), and checks the configurable() attribute of that one. That's how the ECMA spec says the delete operator should behave, so e.g. if I implemented my own custom JSobject type I would expect that virtual method to be called. It also gets rid of code duplication. But then I realised there's a bit more overhead in calling that function (JSString::getStringPropertyDescriptor() creates a jsSingleCharacterSubstring), so I decided against it.
Simon Hausmann
Comment 12 2009-12-04 15:25:11 PST
Comment on attachment 44220 [details] Revised patch (back to basics) and more test cases Kent is not a committer yet. I'm pretty sure he meant to set cq :)
WebKit Commit Bot
Comment 13 2009-12-04 17:21:53 PST
Comment on attachment 44220 [details] Revised patch (back to basics) and more test cases Clearing flags on attachment: 44220 Committed r51724: <http://trac.webkit.org/changeset/51724>
WebKit Commit Bot
Comment 14 2009-12-04 17:21:58 PST
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.