Hacker News new | past | comments | ask | show | jobs | submit login
iOS 12 Safari Array reverse bug (stackoverflow.com)
333 points by wonderfuly on Sept 19, 2018 | hide | past | favorite | 116 comments

Finally we've discovered why people are asked in interviews to reverse an array.

I can also see the bug on macOS with Safari 12.0.

I find it quite worrying that devs already wrote a lib to fix the issue but didn't fill a bug report to Apple and shared it on SO. Anyway, a trendy HN post might be enough to get the attention of some Apple devs and I've pinged a dev just in case: https://twitter.com/ArmandGrillet/status/1042339847384518656

> I find it quite worrying that devs already wrote a lib to fix the issue but didn't fill a bug report to Apple and shared it on SO.

It is worrying... but as someone who has filed my fair share of bug reports to all the major browser projects it's also understandable. Filling good bug reports takes effort, especially for the more obscure ones to produce small and reliable test cases. In my experience only the largest projects have the man power to acknowledge let alone address all bug reports. I abandoned reporting bugs to IE, Edge and Safari long ago because this effort often goes to waste.

I get it though, browsers are one of the largest most complex incoherent pieces of software everyone uses today, but that's also why I think only fully open source (well engaged) projects work well in this area.

As an aside: This is the same reason I think the browser needs to get simple again (without loosing capability) - RE James Mickens thoughts on this. Then browser diversity and man power becomes a moot point.

I’ve reported a few browser bugs myself, none have been fixed (even years later). I’ll still do it, though, because it may help someone else out someday.

According to the linked SO post, it has already been corrected in a technology preview.

You could also just yell into a pillow. Half the time it's just as effective as reporting a bug to Apple without knowing someone there.

You can spend a lot of time writing a good bug report for Apple; it's annoying that they don't bother to respond at all a lot of the time.

I don't understand what the worrying part is. The original poster of the SO question was asking a question. They didn't know if it was a bug or them misunderstanding the intended functionality. The subject literally ends with, "is bug or feature?"

The people who answered it explain that it's a bug, thereby answering the question, and expand as to why they think it's a bug. One person figured out a patch. The bug was already filed and fixed nearly a month ago but doesn't seem to have been released yet to the current versions of Safari.

If there's already a bug filed and marked fixed but you can see that it isn't fixed yet for the people using Safari, and it matters to you, why would sharing it be worrisome?

You could argue that the person who answered with a patch didn't know the bug was already filed with Apple, and so they should have sought out how to file it before sharing it. But I think it ignores how intimidating it can be for someone to file an official bug report with a hugely popular piece of software maintained by one of the largest companies in the world. It's even more intimidating if you've done it before and the report you filed ended up being wrong (many maintainers are not very considerate when responding to mistaken bug reports, which can wreak havoc on a developer's self esteem).

Meanwhile you have platforms like StackOverflow and Hacker News which vastly lower the bar in terms of needing to be right, since they operate more as conversation facilitators than official registers of legitimate bugs. It's much easier to share what you think you've found with a group of your peers, than it is to go on record telling a group of experts that they've made a mistake in the thing that they're experts on.

I don't know if the outcome is worrisome or not, but it definitely seems expected to me... even inevitable.

It's the same reason you talk with your friends about how annoyed you are with potholes not being filled before you take your concerns to a town hall meeting. It's a way to refine your thoughts in a low-stakes settings with peers before formalizing an issue to run up the ladder.

If I must fix it for my users right now I must use a shim. Letting Apple know about this will probably allow me to remove the shim after months have passed. I can see why the priorities are on the shim here.

I also just checked and you need an Apple-ID to report a defect in Safari. Which I for one don't have.

I can’t think of any bug system that doesn’t require you to log in to report a bug.

You're right, requiring sign-up is common for these.

The only bug tracker I use that doesn't have this barrier is the Debian one.

Also the case with any RT-based tracker (Perl core, CPAN), Jira (depending on its configuration, you can create issues via E-Mail), GitLab can also be configured to allow bug creation via an E-Mail address.

On your last point, it takes a few seconds to create an Apple ID and sign up for a free developer account. Both parts together can be done in less than a minute.

And then you have to report the bug yourself as you can't view other people's bug reports, and if they close it as a dupe then you need to ask special permission to view the other bug, and if they grant you access then you can follow it for status updates.

And that's if you can even find the right place to report this kind of thing. Some in this thread are pointing to the webkit bugtracker which I've never used, but I have used and had issues closed as dupes in the apple bugtracker with no real info other than it's a dupe of another link I can't view...

It's not impossible, but it's a lot more time than I could see having to spend on something like this right now.

And I don't think it's fair to criticize someone for not wanting to put that work in, especially if they found a workaround and already posted it somewhere publicly viewable. I'd much rather get a well written bug report from someone that has the time and cares rather than 10 half-assed reports from people who just want to make one so they don't get yelled at or to view the status of another bug.

https://bugs.webkit.org Doesn’t requir an Apple ID and also has public visibility (except security bugs).

Update: the bug has already been filed in both the WebKit bug tracker and Radar, so no need for further reports. https://bugs.webkit.org/show_bug.cgi?id=188794

You get to decide yourself how good of a job to do on your bug reports, so I don’t see where the problem is. If it bothers you that it takes work and you can’t see everything that Apple sees, just let those of us who don’t mind a bit of typing effort take care of it.

>If it bothers you that it takes work and you can’t see everything that Apple sees, just let those of us who don’t mind a bit of typing effort take care of it.

I completely agree, which is why I was just pointing out that the "it only takes a few minutes" is technically true, but a little misleading as nobody is going to be able to write a good bug report, create an apple account, report the bug, have it most likely get closed as a dupe, request access to the dupe, get access to the dupe, subscribe to the issue and wait for it to be fixed and released in "a few minutes".

Whereas making a polyfill could realistically happen in 30 minutes or so, and publishing it to NPM if you feel like it maybe another 10 if you are familiar with the process. And I don't feel like people should be criticized for not wanting to jump through Apple's hoops to report a bug and have it get fixed upstream when the alternative is not only faster, easier, and more public, but also can get deployed to your users right now.

Oh yes it's fast to sign up for one more account with some third-party I don't want to be affiliated with. What's in it for me?

Speaking of that: I do actually maybe have an Apple-ID account because a clueless person with a name similar to mine used one of my Email-Addresses to sign up with Apple.

In theory you absolutely need both, and the library fixes the most pressing issue: that your site might be broken today, and more importantly will remain broken forever, unless the user chooses to upgrade, since Safari does not do automatic over-the-air updates (ala Chrome on desktop) but instead bundles it’s updates with OS versions on mobile, and updates that may or may not be set to automatic on macOS. As such, you should in theory now always have a bug-detect in your code (simple to write, make two identical 2-item arrays, reverse one, check for a difference), and apply the fix if needed.

I think there's a lot of people on SO that try and snipe topics like this to boost their own CV.

I am the publisher of SO, that polyfill answer maybe want to get more star on github. I don't know what's means of the ployfill to this big bug.

Does Apple have a halfway decent public issue tracker? I don’t recall ever seeing one, but I’ve never gone out of my way to look for one either.

I would say it’s exactly “halfway decent”. There’s very little feedback and bugs tend to get closed as duplicates but since it’s not public you can’t monitor the state of the duolicates.

Having had direct experience with this, this is the reason people don't file bugs with Apple. It is an exercise in futility.

I reported a UX bug with the new iOS feature Screen Time when the first developer beta hit. Through the entire beta releases the only updates I got were “we pushed a new release, can you test again?”.

Needless to say the bug made it to the final release of iOS 12. I’m done filling out bug reports for this reason.

Same here. I have a little "blog" where I collect such things (with workaround if any), and then hope google would redirect people there suffering the same issue.

Those people are operating on a flawed understanding of the process though... it’s not futile.

Ask for status updates if you need them. They’re usually prompt and I figure if more people do they’ll start feeling the cost of not automating it.

A year or two ago they started telling you at least the status of the original bug, open, closed or fixed.

That being said, filing bug reports that end up being duplicates is not wasted time, because they aggregate information from duplicate reports into the main report tracking that issue.

For WebKit? Yes https://bugs.webkit.org

No, their bug management is not friendly at all.

Yep it's called radar, it's here: https://developer.apple.com/bug-reporting/

radar isn't public. You need an Apple ID linked to a developer account to view reports.

...which is free and takes about ten seconds to sign up for. You can only view your own reports, but on the other hand they do fix bugs.

This I did not know. Thanks.

Hmm, they must get so many duplicates...

Yeah they get dupes but they encourage them because they aggregate the information so that new information from one report fleshes out the missing information from other reports.

It is public, it's free to use and sign up for. The account costs zero dollars to sign up for, so I don't get the complaint.

It’s the exact opposite of public. You have to have an account, and even then You can only see bugs you submitted.

Yep, Apple takes privacy seriously.

Bug reports sometimes also contain proprietary code that help Apple pinpoint the bug. If you worked for a company and were working on a brand new software product, would you want your competitors to have the ability to search bug reports for your email address (or all addresses at *@xyz.com), knowing that you are having trouble with a specific API?

BTW, Apple Developer Relations has updated its privacy policy for bug reports where data you submit will be deleted from inactive bug reports after a period of time.

A private bug tracker also means that Apple can use the same bug tracker to collect reports about devices or functionality which isn't available to the public.

This I did not know. Thanks.

For webkit? Bugzilla.webkit.org

Last I checked Apple's bug reporting system wasn't public. I really wish they'd change that.

You and many black hat hackers who would love to read through a trove of exploit reports and potentially personal data submitted in uploaded system diagnostics logs.

Security through obscurity is is not useless, but its not much protection either. There are virtually countless open source projects with public bug tracking, many of which are highly public critical internet facing applications used by millions.

It's not necessarily security through obscurity. It's more of a privacy thing and prevents companies from mining bug reports for information about what types of software competitors are working on. Bug reports also contain code and projects that help Apple find the cause of a bug.

The simple solution is a two-tiered system.

The submitter can check "This report is security sensitive or has confidential information that should not be shared further than necessary to fix the bug."

Most projects have this in the form of a default-public bug tracker, and private emails to the developer or security@ mailing list.

It's not difficult to have both private and public bugs where the submitter chooses which is appropriate.

I love it when people think they know better than Apple, and propose simplistic non-solutions as solutions, as if some amazing people at Apple had not already spent countless hours thinking this through at a deep level.

The submitter doesn't always know when they are submitting sensitive or confidential information. And that's not going to be fixed any time soon or with any simple solution. There are system diagnostics reports that can be many megabytes and contain potentially confidential information, and it would be entirely unreasonable to expect a user, even a developer user, to know how to trawl through all of these reports with a level of expertise to discern every possible case of leakage.

And that's just the personal / private information... which, by the way, Apple from what I've seen seems to strive to keep OUT of the diagnostic reports, but that doesn't mean they are perfect at this. And that doesn't even begin to address the information that might be, totally unknown to the submitter, exploitable in other ways.

As far as what other projects have, macOS is a highly complex operating system along with a tightly integrated ecosystem of apps and services, which is designed to, and relied on to, "just work"... while most other systems are either much smaller, or are not maintaining a level of smooth operation and security that can match the "it just works" level of reliability standard that macOS aims for. So maybe the bug reporting systems of all those other projects are appropriate for those other projects, but that doesn't make those systems and their practices appropriate for macOS.

I wasn't talking about security through obscurity, so regurgitating that point helps nothing. It is typical in the industry to keep exploit information under wraps until it is fixed. And the other part of my comment was about personal and private information.

Those countless open source projects aren't up to the same standard as macOS in terms of a combination of complexity plus the expectation of "it just works"... note I said the combination of these two things, not just one of them at a time.

Like the Chromium bug tracker, you mean?

Works on iOS 12.1’s Safari as well, but that’s to be expected assuming that Apple shipped that without knowledge of this bug.

Looks like its been fixed in the new Safari Preview https://i.imgur.com/A6lm25a.png

As noted by someone else (but only as a new top-level comment), this but was already filed and already fixed on WebKit a week ago and is rdar://problem/43637041.

Apparently it’s already fixed in Safari dev preview.

>I find it quite worrying that devs already wrote a lib to fix the issue but didn't fill a bug report to Apple

Why should anybody work for a megacorp for free?

This is a strange response. Reporting a bug is likely easier than creating and maintaining a package. It’s also the better solution for users, rather than getting website operators to install yet another lib and then remember to remove it once a fix does land.

If you need the shim anyway to fix it for your users it doesn't particularly matter to you at what point Apple fixes this. The fix will take months to percolate in the best case anyway. It seems you also need an Applie-ID to even report a defect.

So to me the unwillingness to help Apple with this is not a strange response. Especially considering Apple made Safari closed-source.

I find the response weird because the commenter had an unwillingness to do free work for a company yet publishes a package that fixes their mistake.

Writing a bug report is work. Writing the shim is work.

The bug report doesn't fix the problem right away. The shim fixes the problem right away.

Reporting the bug will cause a fix for everybody eventually. Adding the shim will fix it for me.

If we want to be nice to Apple - and get rid of the shim eventually - sure, we write a bug report. But if we can fix it before reporting, that gets priority.

You have a separate comment that decries the use of a polyfill. So what is the solution you’re looking for?

And now we'll have array-reverse-polyfill showing up as a 6th-level npm dependency on our projects for years to come.

Really? Why not write a for loop instead?

Much easier to add a polyfill that uses a for loop than to refactor a large codebase.

Because you're not in control of what polyfills your dependencies (and transitive dependencies) may be using?

It appears this was already reported and fixed in WebKit - https://bugs.webkit.org/show_bug.cgi?id=188794 but not specifically for the Safari browser.

  Array.prototype.reverse modifies JSImmutableButterfly
You have to wonder how an immutable butterfly can be modified?!

Almost all “immutable” types are mutatable by the runtime itself, irrespective of language or environment.

A couple of examples of why “immutable” types are actually mutable:

* string interning - a string may technically be immutable, but identical strings can be coalesced by the runtime. * immutable objects are not generally immortal: the runtime will eventually want to free the data, which means it must be mutable by the runtime.

Basically at the runtime level if you forget to check all the correct flags you can easily do the wrong thing. If you look at the bugzilla report you can see the comment from the apple engineer about needing to fix this particular foot gun.

I would be most grateful if someone could please explain to me what "butterfly" is meant to be ... a metaphor of some sort I assume.

Internal data structure of JavaScriptCore representing objects, presumably called a butterfly because it starts in the middle and spreads in both directions in memory. One side is properties of the object, the other members of its array aspect.

See e.g. http://phrack.org/papers/attacking_javascript_engines.html section 1.2

This presentation has some nice illustrations: http://www.filpizlo.com/slides/pizlo-dls2017-vmil2017-jscvm-... (under “JSC Object Model”).

An inadvertent yet apt Bradbury reference

I wonder how comparable the situation is to jq, which also does CoW / immutable data. In jq, when a datum has only one live reference, changes to that datum actually mutate the datum. A C example is probably necessary to make this clear:

  jv v = jv_array();  // ref count == 1
  v = jv_array_append(v, jv_number(0)); // Ostensibly copy
  v = jv_array_append(v, jv_number(1)); // but actually mutate
Here, in all cases there is exactly one reference to the array `v`, so `jv_array_append()` actually modifies it in place. Do note that `jv_array_append()` returns a new `jv` value though, and that this is necessary to support the copy-on-write case:

  jv v = jv_array();  // ref count == 1
  jv v2 = jv_copy(v); // ref count == 2 now!
  v = jv_array_append(v, jv_number(0)); // Copy!
  // Now `v`'s ref count == 1 again (and so does `v2`'s!)
  v = jv_array_append(v, jv_number(1)); // Ostensibly copy, actually mutate
You can imagine similar mechanics in an ECMAScript implementation.

Note that in jq itself this is mostly not something a user ever has to think about because one is always passing modified structures to an expression on the right:

  (.foo = "bar") | ... # this sees .foo == "bar"
but it can be user-visible anyways:

  ((.foo = "bar") | ...), # ... sees .foo == "bar"
   .foo                   # but here .foo is as it was before
Here the last reference to `.foo` happens outside the lexical context of the assignment to `.foo`, so the assignment is not visible. Under the covers this all is made possible by the C jv API's copy-on-write design where functions always consume a reference to their input `jv` values (except `jv_copy()`, `jv_get_kind()`, `jv_string_value()`, and `jv_number_value()`) and return a new `jv` value to replace the one that was "modified".

Thanks so much for linking to the thread; I added a comment to the bug pointing back here asking for further insight.

Hopefully this gets this (HN) thread seen by the right people and messages flying in the right directions internally :)

This bug is very much like the most common mistake I see on Common Lisp stack overflow where one tries to mutate constant (quoted) data.

However JavaScript has no similar notion of constant data but implementations try to infer it as an optimisation. In this case that inference was wrong.

I think the memory structure looks something like:

  arr -> box1 -> 1,2,3,4

  arr -> box1 -> 4,3,2,1
But the data occupying the same region of memory before and after the sort. So then when the page is refreshed the JavaScript doesn’t change and the literal data must be included in the “parsed/compiled” form that is reused and so it is initialised as

  arr -> box2 -> 4,3,2,1
The correct behaviour should be as follows:

  1. arr -> box1 -> loc1: 1,2,3,4
  2. Reverse
  3. arr -> box1 -> loc2: 4,3,2,1
  4. Refresh
  5. arr -> box2 -> loc1: 1,2,3,4
The “box” corresponds to the JavaScript object for the array (so mutating the array data can change the box, the data it points at, but not just the reference “arr” as the object might be pointed to from elsewhere). And this box has another pointer to the data for the array (and presumably some bit flag to say whether that is copy-on-write or not). This allows for more efficient array functions when the data doesn’t actually change

The weirdest thing about this is the fact that the bug occurs after a page reload. Does safari cache jit code and the javascript heap/objects between pageloads?

When JavaScript is parsed by jsc, it’s compiled to a cachable bytecode, this includes gc allocated constants for constant expressions - numbers, strings, and the underlying storage for some complex types like arrays and regexps.

The cachable code is kept in a big function source->bytecode hash table.

The cacheable bytecode is then “linked” to a bytecode that is optimized for execution speed. That bytecode has things like create_array, etc that can take the immutable backing store object we generated earlier.

This means that if you have multiple functions with identical source code you only have to do the expensive parse+compile step once, and you end up with multiple independent functions using the same constant/immutable backing stores. This saves memory and helps performance.

Unfortunately it adds complexity - now the mutable is objects have “immutable” backing stores, so you have to implement copy-on-write semantics in order to not share state between different instances of the linked code. In this case it appears that a required CoW check was missing :(

It has a bfcache which attempts to restore page state when going backwards/forwards. My guess would be there's something wrong with the cache behaviour, leading it to restore the old heap and re-execute the JS.

It might just not clear the JIT cache if you reload the page.

I think Apple has to consider separating Safari (and other bundled apps) from the iOS release so that users can update a quick fix through the App Store without waiting for a new iOS update.

There was a serious WebAssembly regression in iOS 11.2 that makes wasm effectively useless [1]. Devs had to disable wasm and wait for months until iOS 11.3 is released.

Apple never releases a iOS hot fix just for a single Safari bug. Then why Apple don't let users to update Safari separately?

[1]: https://bugs.webkit.org/show_bug.cgi?id=181781

Because this isn't "a single Safari bug." It's a bug in JavaScriptCore, which is a public system framework. Safari uses it, but so does any other app which links against it.

Fixing this bug requires shipping new versions of system frameworks, which is pretty much the definition of an OS update.

Or, they could bundle a separate version of the WebKit frameworks just for Safari (like the Safari Technical Preview does) – but then loading a website in your app would use a different stack of frameworks than loading that site in Safari, and no one wants that either.

That makes sense. I didn't know the Apple's system framework structure. Thanks for the explanation.

Bug does not trigger on "Safari Technology Preview Release 65 (Safari 12.1, WebKit 13607.1.5.2)" on macOS 10.13.6. Fixed already, or not yet introduced?

The shipping Safari is 606, the preview Safari is 607. So 'not yet introduced' seems unlikely.

It appears to be fixed at HEAD and in Safari Technology Preview per https://bugs.webkit.org/show_bug.cgi?id=188794

This sounds like a very bad bug, I wonder how bad it is "in the wild".

I suspect bad. Literal data is common. Reversing is (reasonably) common. The spec required that whenever one constructs data with a literal the resulting object will have a different identity, and that (regular) arrays with different identities do not alias.

I wonder if `splice`, `shift`, `unshift` and other methods that modify arrays in-place are also affected.

I've played with it a bit and no it doesn't. Also any modification to the original array before calling `reverse` makes bug disappear

Good to know, thanks for testing!

Woah. I think I ran into this last night after updating to Safari 12 on macOS. I was typing my message into messenger.com (facebook messenger), and all of my typing was reversed. I even took a photo of it

Are you sure it wasn't accidental Right-to-Left input?

I'm not seeing Safari 12 in the App Store (macOS 10.13.6). I wonder if they pulled the update because of this? I have Safari 11 still but my colleague got Safari 12 through the App Store.

Safari updates on Mac come down as part of system updates, so until the Mojave timeframe updates appear

I got the update for Safari yesterday, and i'm still running High Sierra

Safari and webkit updates are pushed out to at least one, maybe two? (not sure exactly how many) major releases.

Isn't this part of the faster loading that some Web browsers do? Essentially the idea is that the browser muddies the idea of a closed page in favour of being able to restore it faster.

It shouldn't be black-box observable like this.

This is a bug, plain and simple (a missing cow check)

Should we hold off on updating then?

>I wrote a lib to fix the bug. https://www.npmjs.com/package/array-reverse-polyfill

everyday we stray further from god

What is extra frustrating is that this is an answer StackOverflow. The whole point is to give clear, educational explanations. Well, the solution is only 21 lines, so why not explain the code snippet instead?

    (function() {
      function buggy() {
        function detect() {
          var a = [0, 1];
          return a[0] === 0;
        return detect() || detect();
      if(!buggy()) return;
      Array.prototype._reverse = Array.prototype.reverse;
      Array.prototype.reverse = function reverse() {
        if (Array.isArray(this)) this.length = this.length;
        return Array.prototype._reverse.call(this);
      var nonenum = {enumerable: false};
      Object.defineProperties(Array.prototype, {
        _reverse: nonenum,
        reverse: nonenum,
Look at how elaborate the repo is by comparison:


It has a nice logo though I can't find a link to the merch store or author's Patreon.

? The snippet you showed is literally the exact code of the module: https://github.com/fanmingfei/array-reverse-ios12/blob/maste...

The rest is just tests / npm config / license

When I posted this, the snippet was not part of the answer being discussed. There was only a link to a node module.

> answer StackOverflow ... the solution is only 21 lines, so why not explain the code snippet instead?

You answered your own question. Especially in the JS world

I was so offended I raised an issue just to throw a strop: https://github.com/fanmingfei/array-reverse-ios12/issues/16

Also if now everyone starts to polyfill this garbage, then apple will not patch it before the next release of iOS.

Fixed. Scheduled. Coming to iOS 15 in 2022...

This has already been fixed in Safari Technology Preview, and Safari usually tails a release behind.

Yay for the incredibly slow bi-yearly update schedule.

Safari updates significantly more often than twice a year.

Does Apple not believe in unit tests or something? This and the password login bug from a few months ago make me pretty concerned.

Webkit has hundreds of thousands of tests running on every check in (check build.webkit.org iirc).

Checking arbitrary complex interactions isn’t trivial so more complex classes of bugs can only get testing when they’re discovered.

Now they will release iOS 13 for this :)

P.S. https://www.youtube.com/watch?v=uG8bNDw6Ftc

Ironically, I got an ad banner for Apple at the top of this page. Saying "Engineer in Europe. Innovate at Apple."

However, this bug sounds pretty serious! :-S

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact