[HN Gopher] System memory allocator free operation zeroes out de...
___________________________________________________________________
System memory allocator free operation zeroes out deallocated
blocks in iOS 16
Author : ingve
Score : 140 points
Date : 2022-09-21 07:43 UTC (1 days ago)
(HTM) web link (mjtsai.com)
(TXT) w3m dump (mjtsai.com)
| dcow wrote:
| It seems totally fine to me that software needing the performance
| of non-zeroed deallocations can implement its own pool itself for
| the critical path in the code that needs it.
| noobermin wrote:
| Yeah, everyone complaining about zeroing taking time are
| ignoring that this should be a sane default, and for fucks sake
| if you need performance you shouldn't be constantly malloc'ing
| and free'ing on the heap in your critical path anyway. I guess
| that bias was built into me because I learned C from tutorials
| written in the 90s where they kept stressing heap is slow
| somehow because it was on a P3 I guess.
| ncmncm wrote:
| Allocators really were slow. I.e. it was easy to write a
| general-purpose allocator 10, 100, or (on SGI Irix!) 1000
| times faster than what their libc did.
|
| Nowadays it takes work to get more than 10x, but hardly any
| to get there.
| [deleted]
| secretsatan wrote:
| I thought accessing deallocated memory would crash an app anyway?
| secretsatan wrote:
| I see, I rarely use lower level stuff like this, so don't
| encounter it much, but, when I have to, I would get
| deallocation errors when dealing with things like metal buffers
| and just assumed the system always took care to protect the
| memory.
| klodolph wrote:
| It can be a bit mysterious until you look at how it works.
|
| Most CPUs provide memory permissions with granularity of
| pages, which are usually 4 KB in size. The OS manages these
| by modifying a "page table" which the CPU uses. Changing the
| page table is not free, so the userland allocator
| (malloc/free) will request large blocks of memory from the OS
| (with mmap) (or sbrk, if you're a dinosaur) and then divide
| them up into smaller blocks for your program. They typically
| remain accessible until the entire original block is freed.
|
| If you allocate a large enough block of memory, it will
| typically just be backed by one region of pages made with
| mmap. Then, when you free it, the allocator will munmap it.
| You can test this out by allocating a large block of memory,
| freeing it, and then dereferencing it.
|
| Your system might do this for 1 MiB allocations, for
| example... change the allocation size and see whether it
| still crashes. #include <stdio.h>
| #include <stdlib.h> int main(int argc, char **argv) {
| volatile int *ptr = malloc(1024 * 1024); puts("*ptr
| = 1"); *ptr = 1; free(ptr);
| puts("*ptr = 2"); *ptr = 2; }
| astrange wrote:
| Pages are 16KB on iOS (and AS Macs). They're 4KB everywhere
| else on the world, which is too small these days, although
| there's things like "superpages" to help with that.
| ncmncm wrote:
| Malloc will not unmap memory. Period. That would have huge
| performance cost in multi-thread programs.
| sumtechguy wrote:
| That depends on the applications CRT and compiler and how they
| are setting up their memory regions.
|
| Some CRT's just go get their own block of memory then malloc
| out of that. Some use the OS extensively to minimize that sort
| of thing. It just depends.
| yakubin wrote:
| That's true for memory which has been unmapped from the process
| (as long as something else isn't mapped to the same virtual
| address range). But different implementations of C
| malloc()+calloc()+free() don't necessarily unmap memory when
| you call free(). Instead they mark it as something that may be
| returned from subsequent calls to malloc()/calloc(), i.e. the
| memory isn't returned to the OS.
| ncmncm wrote:
| None of them unmap freed memory.
| yakubin wrote:
| That depends on the specific implementation. glibc does
| unmap memory[1]. Not in every free() call, but still. There
| are also implementations which unmap in every free(), which
| are used to quickly detect bugs. Honestly, I wouldn't want
| to use an implementation which never unmaps memory. I've
| already been irritated by Go's reluctance to return memory
| to the OS in the past. I'm certainly glad it's less of a
| problem in C. (Although I've read some reports of glibc
| being a bit suboptimal here in multithreaded programs,
| compared to allocators like tcmalloc or jemalloc.)
|
| [1]: <https://github.com/bminor/glibc/blob/a364a3a7090b82dd
| d30e920...>
| ncmncm wrote:
| It won't do that by default. You need to set some non-
| portable flags to get it to munmap things.
|
| Unmapping trashes page-map caches of other threads in the
| process. That involves inter-core interrupts. Not pretty.
| yakubin wrote:
| Example program: #include <stdlib.h>
| int main() { for (size_t i = 0; i < 4096*4096;
| i++) { void* p = malloc(i * 4096);
| free(p); } }
|
| Running strace on it gives me a whole spam of logs like:
| mmap(NULL, 139264, PROT_READ|PROT_WRITE,
| MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0e7d46f000
| munmap(0x7f0e7d46f000, 139264) = 0
| mmap(NULL, 143360, PROT_READ|PROT_WRITE,
| MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0e7d46e000
| munmap(0x7f0e7d46e000, 143360) = 0
| mmap(NULL, 147456, PROT_READ|PROT_WRITE,
| MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0e7d46d000
| munmap(0x7f0e7d46d000, 147456) = 0
| mmap(NULL, 151552, PROT_READ|PROT_WRITE,
| MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0e7d46c000
| munmap(0x7f0e7d46c000, 151552) = 0
| mmap(NULL, 155648, PROT_READ|PROT_WRITE,
| MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0e7d46b000
| munmap(0x7f0e7d46b000, 155648) = 0
| mmap(NULL, 159744, PROT_READ|PROT_WRITE,
| MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0e7d46a000
| munmap(0x7f0e7d46a000, 159744) = 0
|
| That was run under a standard Debian 11 installation.
| 323 wrote:
| You can think of two levels of deallocated memory: deallocated
| just inside the app, and fully deallocated towards the OS. Only
| the fully deallocated towards the OS will crash.
|
| When you deallocate small amounts of memory, the underlying C
| library allocator will keep the deallocated memory around and
| not return it to the OS in case you need a similar sized piece
| of memory soon.
| ncmncm wrote:
| Not correct.
|
| It is very rare for memory ever to be freed to the OS before
| process exit. Malloc never does.
|
| And, zeroing the memory, if code later uses it like a
| pointer, that will be null and the use will trap.
| maldev wrote:
| I know the apple documents note this for the release. But we
| spent a bit today at work trying to do it, and we couldn't build
| a test case. Has anyone actually tested this? The kernel already
| has their own tagging system which poisons things, so I assume
| this is a usermode thing.
| Wowfunhappy wrote:
| Is there a reason they aren't making this change only for apps
| compiled with the latest SDK?
| kevingadd wrote:
| Security, probably. UAF attacks are going to be slightly harder
| to perform if the data you put there is zeroes now.
| rs_rs_rs_rs_rs wrote:
| >UAF attacks are going to be slightly harder to perform
|
| SOME attacks are going to be harder, others are going to be
| easier(at least that's what a Project Zero researcher thinks)
|
| https://twitter.com/ifsecure/status/1572902862128295937
| kevingadd wrote:
| That appears to be the effect of changes to calloc, though.
| The change to free is a security improvement.
| jeffbee wrote:
| If they "worked until now" doesn't that imply that the app
| ecosystem makes too little use of sanitizers like ASAN?
| Sanitizers will stomp on deallocated regions, and much much
| more.
| yakubin wrote:
| Does iOS use different libc dynamic libraries for applications
| compiled with different SDKs? I'm not an iOS developer, so I
| don't know, but I would assume there is only one
| _libsystem_c.dylib_ [1] on iOS.
|
| [1]: Or even 0, as in Big Sur, where it's provided inside the
| runtime linker(/loader), instead of being a separate file.
| saagarjha wrote:
| Usually no.
| TheTon wrote:
| They don't (usually) have different versions but they do have
| "linked on or after checks". So one libsystem, but it can
| look at the sdk the software was built against and adjust its
| behavior accordingly. But I have no idea if they're doing
| that here.
| josho wrote:
| Yes. This protects your data against a malicious app. Your
| proposal gives a malicious app a workaround to avoid this.
|
| Is there a reason you don't want this on by default?
| [deleted]
| kllrnohj wrote:
| No it doesn't. Malicious apps aren't impacted by this at all.
| It's a hardening technique for non-malicious apps to help
| protect them against malicious inputs. Which any maintained,
| updated app would naturally just get when they update, and in
| the meantime there's no regression in security from previous
| releases.
|
| It's only on-everywhere because Apple doesn't do backwards
| compatible. Update or get kicked out is the expectation.
| josho wrote:
| Aren't both benefits?
|
| E.g. a malicious app mallocs a large buffer and just reads
| the memory looking for anything interesting? AND as you
| pointed out a non-malicious app that doesn't handle input.
|
| > It's only on-everywhere because Apple doesn't do
| backwards compatible.
|
| If this causes issue in an app then doesn't it mean that
| app has a possible vulnerability? So, it can be argued that
| breaking an app is increasing the security of the
| ecosystem. And yes, I understand the other side too of
| having an obscure app that you depend upon breaking because
| it is no longer supported. That's also the type of app that
| doesn't have a high probability of being exploited.
| esprehn wrote:
| > E.g. a malicious app mallocs a large buffer and just
| reads the memory looking for anything interesting?
|
| No, the OS zeros pages before giving them to a new
| process, otherwise you'd have all kinds of information
| leaks across security boundaries.
|
| You only see dirty memory within the same process when
| you malloc and then free and malloc again and get a page
| from the free list within the process. Increasingly
| allocators are zeroing those too though to reduce the
| attack surface from malicious inputs (which is what
| changed in iOS).
| kllrnohj wrote:
| > If this causes issue in an app then doesn't it mean
| that app has a possible vulnerability?
|
| Only if the app had any untrusted inputs in the first
| place. If the app doesn't ever touch the network or only
| connects to its own servers then no, it's not really
| improving security.
| mzs wrote:
| Wait, what calloc (3) no-longer zeros though?
|
| >Memory Allocation
|
| >Known Issues
|
| >The system memory allocator free operation zeroes out all
| deallocated blocks in macOS 13 beta or later. Invalid accesses to
| free memory might result in new crashes or corruption, including
| NULL-pointer dereferences and non-zero memory being returned from
| calloc. (97449075)
|
| https://developer.apple.com/documentation/macos-release-note...
|
| edit: I guess this is taking advantage of use-after-free being
| undefined behavior.
| syntheticnature wrote:
| I'm not sure I see it as "taking advantage of"; if code is
| engaging in the UB of writing to invalid pointers, there could
| still have a race condition where calloc() appears to be
| returning non-zeroed memory, simply because the invalid pointer
| write happened after the clear. This just moves the clear back
| in time.
| cesarb wrote:
| From what I understood, the trick is that, for a block which
| was returned by free() and later returned by calloc(), the
| former behavior was to zero within the calloc(), while the new
| behavior would be to zero within the free(). If there's a bug
| which writes to the memory after the free() but before the
| calloc(), the former behavior would mean it's still zeroed, but
| the new behavior would mean it ends up overwritten with
| something which isn't all-zeros.
| monocasa wrote:
| calloc(3) isn't the only way to allocate memory, nor the most
| common one in ObjC apps.
| astrange wrote:
| Actually, ObjC objects are allocated with calloc() so it
| might be the most common one.
|
| It also has a better interface than malloc() because it can
| check for overflow evaluating `size*count`, though it'd be
| even better if C had first-class types and you could pass
| that in.
| ecpottinger wrote:
| It is the default I wish in all de-allocations no matter what OS
| you are talking about.
|
| That way there is no 'dead' data to be probed for.
| xani_ wrote:
| Well, it's also waste of time and if your app is constantly
| allocating and deallocating stuff it would take a lot more.
| jacobsenscott wrote:
| If you are concerned about performance at that level you
| likely shouldn't be allocating and de-allocating memory all
| the time, as that is slow even without zeroing. You should
| use a memory pool to allow re-using your allocated memory.
| seiferteric wrote:
| seems like something that could be handled at the
| memory/controller level instead of wasting CPU cycles writing
| 0's.
| astrange wrote:
| It can be faster or slower, it's a wash at worst if you're
| calloc()ing later anyway, and it helps swap (or memory
| compression on swap-less iOS).
| alcidesfonseca wrote:
| Is there any way of measuring how many apps were affected by this
| change?
| mcraiha wrote:
| Apple crash reports will measure this (if you compare old
| reports to new ones), but the data isn't public. I assume some
| third party SDKs will get updates to fix their bugs (and
| changelog might reveal it) but otherwise it is hard for normal
| user to see what issue caused an app to crash.
| cesarb wrote:
| I wonder how long until programs start to accidentally depend on
| it, the same way some programs currently accidentally depend on
| freeing memory not immediately overwriting it.
|
| For instance, I can imagine a program which accidentally follows
| a dangling pointer to an already freed structure, and reads
| another pointer from within that structure, not crashing because
| it ends up checking this later pointer against NULL... until the
| stars align and the memory used by the freed structure has been
| returned to the operating system, or overwritten by a later
| allocation.
| pjscott wrote:
| I urge anybody using a C family language to become familiar
| with AddressSanitizer [1], a tool that (with support from the
| compiler) detects an impressive variety of memory bugs at
| runtime. The scenario you describe would result in the program
| immediately crashing with a read-after-free error, along with
| stack traces for the most recent calls to malloc and free that
| involved that address. It's remarkably useful and
| straightforward, and Apple's tooling has good support for it,
| along with Xcode integration [2].
|
| [1] https://clang.llvm.org/docs/AddressSanitizer.html
|
| [2]
| https://developer.apple.com/documentation/xcode/diagnosing-m...
| rock_artist wrote:
| I'm using sanitizers on macOS for few years now. Doing cross-
| platform, ~~it really feels inferior~~ I really miss them on
| MSVC side. (wrt to exclusive asan since VS2019)
|
| Still, in some cases you have some tiny uninitialized member
| for example that is much harder to find. So with this malloc
| it might even cover those more.
| dlundqvist wrote:
| This. I personally think ASAN and it's friends are some of,
| if not the, best things to happen to C/C++ in the last
| decade. We use it at work, I use it in all my personal
| projects. We've found "countless" bugs with ASAN together
| with LSAN.
|
| It should be part any project from the start, run as much as
| possible with ASAN when the performance hit can be afforded.
| pseudoramble wrote:
| Just confirming, but you're taking about Leak Sanitizer?
| https://clang.llvm.org/docs/LeakSanitizer.html. Not really
| familiar with these tools, definitely not the acronyms.
| dlundqvist wrote:
| Sorry, yes, I meant Leak Sanitizer.
| pseudoramble wrote:
| No need to be sorry! I appreciate it!
|
| It was actually in the link the parent posted. I just
| missed it at first.
| gavinray wrote:
| "the same way some programs currently accidentally depend on
| freeing memory not immediately overwriting it."
|
| Maybe a dumb question, but what do you mean by this? Could you
| give a C/C++ pseudo-example?
| wnissen wrote:
| Ooh, I have a good one for this. If you have a C++
| `std::string` object passing into a C API that takes a null-
| terminated `char *`, there's a convenience method
| `std::string::c_str()` to produce the C string from the C++
| one. char const* inputFilename =
| std::string("path/to/file").c_str();
| call_to_C_API(inputFilename);
|
| Boom. You can typically access `inputFilename` until the next
| allocation on the stack, but it will almost always go bad
| quickly. This isn't allocation on the heap, which usually
| requires another level of indirection, but you get the idea.
| cesarb wrote:
| > This isn't allocation on the heap, which usually requires
| another level of indirection, but you get the idea.
|
| Isn't it allocating in the stack due to the "small string
| optimization"? Making string contents longer (or using a
| C++ standard library which doesn't have a "small string
| optimization" in the first place) would be enough to have
| it be allocated in the heap instead.
| verall wrote:
| No, with longer string contents the std::string will
| internally allocate and store on the heap, but as the
| containing std::string is a temporary it will be pop'd of
| the stack (stack pointer moved, which is why it works
| "sometimes") and its destructor called at the end of the
| statement (at the semicolon), freeing the heap allocated
| memory (which, as parents are discussing, may still work
| because nothing has yet overwritten the recently freed
| memory).
|
| Changing it to:
| call_to_C_API(std::string("path/to/file").c_str());
|
| Makes it valid because the std::string object will live
| until the semicolon.
| [deleted]
| Someone wrote:
| Not the poster, but it's fairly easy to accidentally do the
| equivalent of free(f); f->close();
|
| in code that does a few malloc, if/else's, etc. between those
| calls. Stuff like that gets hard to spot in more complex
| code, especially in the presence of C++ copy constructors,
| move constructors, etc, where the compiler helpfully inserts
| that call to _free_ for you.
|
| Bugs in copy constructors also can lead to double frees when
| the destructors of an object and its copy both call _delete_
| on a pointer that they think they exclusively own. Between
| those two destructor calls, you can easily get a use after
| free. Example: https://stackoverflow.com/a/64014035
|
| If the allocator doesn't change the content of freed blocks,
| such bugs can go unnoticed, making the program "accidentally
| depend on freeing memory not immediately overwriting it".
| ajross wrote:
| > especially in the presence of C++ copy constructors, move
| constructors, etc,
|
| You only mean the former, not both. The only reason for the
| existence of the giant rats' nest of complexity that is C++
| move semantics is eliminating this particular mistake.
| tlb wrote:
| On Mac, malloc has several options to help find such bugs. If
| you set MallocScribble=1 in the environment, it fills blocks
| with 0xaa on alloc and 0x55 on free.
|
| On Linux, running `env MALLOC_PERTURB_=43605 myprogram` will do
| the same.
| speedgoose wrote:
| That should be the default behaviour, perhaps with random
| values too.
| kergonath wrote:
| It's easier when it is a specified value. Easier to see in
| a debugger and to diagnose. Sure, it can occasionally be
| interpreted as meaning something, but so can random
| gibberish. As long as everything is overwritten, there is
| no privacy issue.
| cesarb wrote:
| > Sure, it can occasionally be interpreted as meaning
| something, but so can random gibberish.
|
| Some gibberish is better than others. For instance, on
| x86 (64-bit, 32-bit, or even 16-bit), filling with the
| 0xcc byte means that, if executed as code, it will trap
| (0xcc is the single-byte INT3 "single-step breakpoint"
| instruction). And for most Unix-style operating systems,
| which put the kernel in the high half of the address
| space, the filler bytes should have the high bit set, so
| that treating them as pointers will trap (the pointer
| will have its high bit set, pointing to kernel memory,
| which user space is forbidden from accessing).
| arcticbull wrote:
| Having a different pre-defined value for allocation vs
| deallocation scribble is nice because you can then tell
| if the error happened pre-initialization or post-free.
| $AA and $55 also weren't chosen by accident one assumes,
| $AA is 1010_1010 and $55 is 0101_0101. Consistent values
| help with reproduction.
|
| The Linux setup where you can choose your own scribbles
| seems to meet your needs no?
| wokkel wrote:
| Or just use valgrind.
| speedgoose wrote:
| Or just use a memory safer programming langage.
| bayindirh wrote:
| If your use case fits into capabilities of such language,
| and you have the necessary libraries, and bindings, etc.,
| then why not?
| saagarjha wrote:
| > For instance, on x86 (64-bit, 32-bit, or even 16-bit),
| filling with the 0xcc byte means that, if executed as
| code, it will trap (0xcc is the single-byte INT3 "single-
| step breakpoint" instruction).
|
| Trying to execute off the heap is going to trap anyways.
| saagarjha wrote:
| It's slower.
| CGamesPlay wrote:
| For the confused, 43605 in decimal is 0xaa55 in hexadecimal.
| diebeforei485 wrote:
| This is better than the status quo of use-after-free being
| abused for security exploits as part of an exploit chain for
| sandbox escape.
| cpeterso wrote:
| As long as Apple's allocator continues to zero freed memory,
| programs accidentally depending on that behavior will only be a
| problem for other operating systems.
| Taniwha wrote:
| Possibly but there's the potential reverse problems where
| Apple programs start depending on newly allocated memory
| being zero .... and those programs start failing elsewhere
| ...
| ncmncm wrote:
| Might fail there, too, but only sometimes, if the memory
| gets allocated again.
| cesarb wrote:
| > As long as Apple's allocator continues to zero freed
| memory, programs accidentally depending on that behavior will
| only be a problem for other operating systems.
|
| As I mentioned, only until that freed block is reused for a
| new allocation, which means it will no longer be all-zeros;
| or until the memory allocator decides it's time to unmap that
| region, which means it will trap (SIGSEGV or similar).
| kergonath wrote:
| > which means it will trap
|
| Is it really a problem? Failing harder and earlier is a
| good thing if it means the bug has more chances of being
| detected and fixed.
| ncmncm wrote:
| Memory allocators generally don't unmap anything, because
| the performance hit on any other threads running is severe.
|
| When memory is unmapped, caches of memory mappings of other
| threads are discarded, via inter-core interrupts. Then they
| get misses until their cache is restored.
|
| In what might be a multi-thread program, you don't fool
| with the memory map without very good reasons. Mapping new
| pages, or marking a page r/o or r/w is OK; anything else,
| probably not.
| zerohp wrote:
| > When memory is unmapped, caches of memory mappings of
| other threads are discarded, via inter-core interrupts.
|
| ARM architecture does not need to interrupt for TLB
| shootdown.
| ajross wrote:
| Or until the particular allocation moves to a custom/separate
| heap or other non-system-malloc allocator. That sort of
| tuning is very common in big apps.
| shaggie76 wrote:
| I wonder how many projects will be oblivious because they use
| their own allocator (eg: we use a modified version of Doug Lea's
| allocator).
|
| If the system allocator gets slower people might be more inclined
| to switch to something custom or use locally recycled allocations
| which may make use-after-free bugs even harder to find.
|
| I'm sympathetic but I wonder if it would be more sensible as an
| option that's on by default instead.
| saagarjha wrote:
| There is apparently no performance degradation due to other
| improvements in malloc.
| Hackbraten wrote:
| Why should the system allocator get slower?
| MarkSweep wrote:
| Zeroing memory takes longer than doing nothing.
|
| Though some chips optimize zeroing memory. For example Intel
| does, perhaps Apple does as well?
|
| https://travisdowns.github.io/blog/2020/05/13/intel-zero-
| opt...
| saagarjha wrote:
| Apple uses dc zva on ARM.
| trasz wrote:
| Sounds similar to what jemalloc (default libc allocator in
| FreeBSD) calls "junk filling".
| Semaphor wrote:
| Tangent
|
| > Hopefully you aren't relying on any abandoned software.
|
| Every major Android update, I get scared. I use an alarm clock
| (Gentle Alarm) that has far more features than all others, but
| it's been long abandoned (as in: removed from the play store, all
| websites dead. This was a paid app). Android 10 or 11 already
| broke it, but someone on reddit (where all 4 or so users of the
| app met :D) found a manifest change and allowing "drawing over
| other apps" to fix it.
|
| Now it works on 12, but after I already spent hours asking on HN
| and Reddit for a maintained replacement and testing those, I hope
| this continues, because with how lacking all others are I'd
| rather learn Android development and program my own replacement
| than using something else.
|
| edit: Hah! The thread [0] with the fixed APK is still getting
| comments from people who found it every few months :D
|
| [0]:
| https://old.reddit.com/r/androidapps/comments/i01xh3/gentle_...
| xani_ wrote:
| I use starfield as screensaver since pretty much first android
| phones, just keep old APK from few years and it still works
| wazoox wrote:
| What's so special about that app? So that we know
| Semaphor wrote:
| > When setting the alarm, by default I want to have the
| option to set it in hours/minutes from now. So instead of
| setting the alarm for 04:30, I want to tell it to set it in
| 6h30m from now.
|
| > I need it to allow me to set a time of X minutes during
| which it gets louder until it reaches the pre-set volume.
|
| > pre-alarm: It's an alarm that goes off X minutes before
| your main alarm, at a very low volume, with its own settings
| of volume, time to reach full volume, media to play, etc.
|
| From my Reddit thread [0] back then. It was the upgrade to 10
| that did it.
|
| [0]: https://www.reddit.com/r/androidapps/comments/jvbsuz/loo
| king...
| dylan604 wrote:
| Isn't setting an alarm a distance from now vs a set time
| called a "timer"?
| macrael wrote:
| I use alarms instead of timers for most things because of
| snooze. For stuff like laundry, this is critical to me
| because I often will turn off a timer's alert thinking
| "I'll get to this in a minute" but without snooze I
| forget until the next morning.
| Semaphor wrote:
| Technically, I guess? But it behaves exactly like an
| alarm (it is actually just the input, if it's 13:00, and
| I set the alarm-timer for 6h, the app will set an alarm
| for 19:00, not a 6h countdown).
| tambourine_man wrote:
| This looks awesome. It's the perfect example of way too
| many features for a built in app, which is supposed to be
| used by the general public, but a wonderful fit for a very
| specific niche that should be addressed by third party.
|
| I feel you and that's why we need more open source
| software.
| Semaphor wrote:
| Several of those features have subfeatures, and then
| there are more that I don't use. It's exactly my kind of
| app, one that does everything, and everything well ;)
|
| My favorite Windows apps are the same (MediaMonkey,
| EmEditor, and DirectoryOpus), paid apps with tons of
| features, more than I need, but also all that I need.
| ezfe wrote:
| For your first note, if I ask Siri to "Set an alarm in 6
| hours" it does that (yes, I know you're talking about
| Android, but I assume Google Assistant does the same)
| jeroenhd wrote:
| Google Assistant will set an alarm for ${currentTime} + 6
| hours in your standard alarm app (can by Google's clock,
| can be your app of choice). Depending on your app of
| choice, this can have the effect of polluting your list
| of alarm presets with one-off alarms that you'd need to
| delete later.
| Semaphor wrote:
| But the feature in Gentle Alarm works with all its other
| features, specifically alarm profiles that have different
| settings depending on what I need at the moment (sleeping
| alone, sleeping next to my wife, napping).
|
| In addition, I'm already trying to get rid of Alexa, I
| really don't want to add another voice assistant.
| thetinguy wrote:
| I have seen release notes about automated fixes Apple
| themselves for apps in the App Store that haven't been updated
| recently.
| Wowfunhappy wrote:
| This is a problem with how we treat backwards compatibility on
| mobile operating systems. Imagine if this was an app for
| Windows. Would you still be scared of updating?
|
| This is why no one ever pays more than a couple bucks for a
| mobile app. That would be a terrible investment, as the app
| could break at any time!
|
| Similarly, this is why mobile will never be a good platform for
| traditional single-player video games.
| [deleted]
| [deleted]
| culopatin wrote:
| But then in the case of Windows we complain that Windows
| releases in 2022 still have stuff that looks like Windows
| releases from 2002. Maintaining that backwards compatibility
| can become a massive pain too.
| VancouverMan wrote:
| Those tend to be the most usable parts of recent Windows
| releases. It comes as a relief to encounter them.
| jeroenhd wrote:
| I've seen several remnants of Android 2.1 or below in my
| Android phone in settings and dialogues that don't need
| much maintenance. They're reskinned easier, but they are
| there!
| jeroenhd wrote:
| While you're right that Microsoft has a much better track
| record for backwards compatibility, this isn't just limited
| to mobile operating systems. See: Apple breaking x86,
| deprecating OpenGL, switching platforms, disabling drivers,
| etc.
|
| Most things that actually break on Android break for good
| reason, in my opinion. I consider giving apps the ability to
| draw overlays without any kind of permission in a supposedly
| sandboxed environment a design flaw, for example. I'm more
| annoyed by their restrictions on dynamic loading but even
| that still seems to work fine if you avoid the Play Store and
| set your API targets to a version that triggers the backwards
| compatibility system.
|
| The recent change to the way uploading to Google Play works
| (where you have Google sign your apps instead doing it
| yourself) is the worst change in years, but that's
| technically a Google change, not an Android change.
|
| Almost all API changes necessary to run old apps are minute.
| The permission overhaul for Android 6 (interactive
| permissions for many permissions that were previously granted
| install-time) requires a few more lines of code to show an
| error if the user denies a critical permission but it doesn't
| require a full rewrite.
|
| The consequence is that app devs with some minimal time on
| their hands can update their apps to work on modern devices
| quite easily. Only apps that are thrown over the wall and
| abandoned or created by defunct companies are now broken.
|
| Luckily, decompiling most Android apps is quite trivial. If
| the app is indeed completely defunct with the company
| disappearing, one might relatively safely maintain a
| decompiled fork of the abandonware to make it work on modern
| platforms.
|
| It's a pain, but not a dissimilar amount of pain to searching
| working on NoCD cracks for games that require DRM broken on
| Windows 10. Enthusiasts do it, quite regularly as it turns
| out!
|
| This is also why I'm in favour of laws about source control
| for abandonware; if a company doesn't exist anymore and
| people still use their software, the source code should be
| opened so customers aren't screwed over. Source escrow isn't
| unheard of in B2B applications and I don't see why it can't
| be done for consumer apps.
| sgtnoodle wrote:
| Re: source code release, it seems like that could get
| rather messy for anyone using third party source code that
| isn't open.
|
| Also, right away any sort of law like that would become
| incredibly nuanced. I have a pacemaker and there's an
| optional BLE app for it. Security through obscurity is
| lame, but I'd rather that app's source code not be dumped
| on the internet if the pacemaker company stops supporting
| it. The source code wouldn't keep the app going because it
| is dependent on the cloud, and would only be of value to
| folk trying to reverse engineer the diagnostic protocol.
| Personally that sounds like a lot of fun, but it's also
| hardwired into my heart...
| Wowfunhappy wrote:
| On the other hand, something wired into your heart
| probably shouldn't rely on a proprietary app from a for-
| profit company that could drop support at any time...
| kllrnohj wrote:
| Android's backwards compatibility, especially for apps that
| don't update, is quite solid. The cases where previously
| working behavior is broken without requiring the app to "opt-
| in" to the breakage is generally scoped solely to things that
| are considered abuse vectors. Which "draws over other apps"
| unfortunately is.
|
| It's not as good as Windows' back compat, no. But then again
| nothing is, as that's the only platform concerned with
| preserving not just API compatibility but _bug_
| compatibility.
| BoorishBears wrote:
| Android's backwards compatibility is _atrocious_ with a
| capital A.
|
| Every version has random will-be-breaking changes that get
| held off if your app was compiled before said version came
| out, but there's only a release or two before the change
| starts to ignore your compiled version (for example, when a
| massive permissions change comes down the pipe, any app
| that's compiled against the newest SDK breaks immediately,
| and apps that were compiled against older ones just get to
| break next release)
|
| And just like any mobile platform, apps heavily rely on the
| OS to provide UI widgets and layout. So even design
| language changes can (and often do) break the UI.
|
| -
|
| What you're probably seeing is what _developers_ are forced
| to work around: the fact that everyone is stuck targeting
| ancient versions of Android because Android users have just
| accepted their devices never getting OS upgrades.
|
| Android Studio will still default to targeting a minimum
| SDK version of API 25. Android 5.0. From November 12 2014.
|
| The situation is so bad that Google removed it from their
| dashboard (https://developer.android.com/about/dashboards)
| and buried it in the IDE: https://9to5google.com/2022/05/20
| /android-2022-distribution-...
|
| Nearly a third of Android devices are on a version of
| Android >5 years old... just imagine if all your iOS apps
| had to target iOS 11 as a minimum feature set, and XCode
| defaulted to supporting iOS 8 for all new projects
|
| When the apps can't rely on any newer features, it creates
| the illusion of backwards compatibility.
| cesarb wrote:
| There's one case I know of where previously working
| behavior is broken, for something which was not an abuse
| vector at all: if your app depends on the hardware "menu"
| button (which is the case for nearly all apps made back
| when having a hardware "menu" button was standard for
| Android), for several versions Android showed an emulated
| software "menu" button next to the back/home/etc buttons,
| but more recent Android versions no longer show that
| button, breaking all these apps (since there's no way to
| get to their menu). See https://www.xda-developers.com/rip-
| menu-button-android-10-dr... for details.
| phoboslab wrote:
| Very true. Apple has removed several of my games (all working
| perfectly fine) because, well, they felt like it:
|
| > Since this app hasn't been updated within the last three
| years [...] it has been removed from the App Store
| musicale wrote:
| I hate this. I don't think it's the right approach to
| improving search and discoverability in the app store. (My
| personal suggestion for instantly improving it 100% would
| be removing ads that eat up the first half-screen of search
| results on an iPhone.)
|
| I also greatly dislike how iOS takes the backwards approach
| of offloading backward compatibility as a yearly support
| burden multiplied across every developer - rather than
| maintaining it in the OS.
|
| Platforms are supposed to absorb developer pain for
| multiplicative benefit - not the other way around.
| kitsunesoba wrote:
| As a developer I'm not sure that I agree. Some degree of
| backwards compatibility is good, but it quickly becomes
| an unwieldy burden that acts as a ball and chain on the
| development of the OS and platform toolkit.
|
| Among modern operating systems, iOS is probably the worst
| in terms of backwards compatibility but it's also one of
| the most pleasant to develop for -- UIKit/Cocoa is
| unrivaled in terms of both breadth and depth. One can
| easily build a top class iOS app with few or no third
| party dependencies, which is not the case on most other
| platforms. I don't think that's a coincidence... if the
| iOS dev team were encumbered with maintaining backwards
| compatibility for upwards of a decade it would be much
| more difficult to build such a complete and polished
| toolkit.
| Wowfunhappy wrote:
| If iOS had versioned libraries and separate teams
| maintaining the older branches, would that really impede
| the modern toolkit? I realize that expanding the scope of
| a project by adding more developers isn't as simple as it
| seems, but I feel like there ought to be an
| organizational/development structure that could make this
| work.
|
| I wouldn't even be opposed to older apps running in some
| sort of seamless-to-the-user virtual machine.
| pram wrote:
| Yeah this is insane. I bought Sonic CD and Sim Tower for
| iOS years ago and they're both just completely gone. Not
| listed, impossible to install. I'm never buying a mobile
| game again.
|
| It blows my goddamn mind.
| ncmncm wrote:
| Probably you should decompile it, instead of starting from
| scratch.
|
| This is made easier because apps are distributed in bytecode
| form, and compiled to machine code on installation. The
| bytecode is retained in the .apk file, IIUC.
| WalterBright wrote:
| When I want to make sure allocated memory gets initialized, I
| have the allocator set it to 0xDEADBEEF.
|
| The trouble with 0 initialization is it can accidentally be
| correct, or can _look_ correct when it isn 't. When your pointer
| is pointing to 0xDEADBEEF, odds are 99.9999% that the data wasn't
| initialized.
|
| D does a similar thing. The default initializer for floating
| point variables is NaN, not zero. There was a debate about this
| in the D forums.
|
| https://digitalmars.com/d/archives/digitalmars/D/Movement_ag...
|
| My position was pretty clear - default initializations should not
| be accidentally correct.
| olliej wrote:
| You get an efficiency problem there in that it means that the
| first thing allocations have to do is re-zero the allocation.
| acdha wrote:
| There's a good history supporting that logic but I wonder if
| there were other trade offs: a couple of the comments around
| this mentioned better memory compression and some optimization
| work which made me wonder whether they might have been able to
| make zeroing faster than a pattern, especially if they're going
| to have some generation of Apple Silicon add hardware support.
| yieldcrv wrote:
| I like the German grammar of capitalizing all nouns
|
| Would that be useful here even in a computer context?
| JoeAltmaier wrote:
| Used to be linux zerod allocated pages only upon first use. But
| the time to take the page fault was _larger than the time to zero
| the page_ so they changed to zero-immediately.
|
| Modern processors zero things very, very fast. This seems like a
| defensible approach.
| ajross wrote:
| Yes, but this is a heap, not a VM. You're not streaming through
| the cache into DRAM, you're polluting the cache with dirty
| lines that the app would presumably like to be using for near-
| future loads. The performance impact is obviously going to
| depend on usage patterns, but it certainly could be much
| higher.
| sedatk wrote:
| On Windows, there's that lowest priority task (Zero Page
| Allocator) whose sole purpose is to zero out the freed pages
| and add them to the available pages list. This way, allocation
| tasks don't have to wait for zeroing.
|
| IIRC, Zero Page Allocator's priority was so low that it was
| even lower than the lowest priority available to Win32 API's.
| mcculley wrote:
| Is zero better than 0xDEADBEEF or just faster?
| CJefferson wrote:
| One advantage is that when you allocate the memory back out
| (either by malloc, or calloc which requires zeroing), you don't
| have to do anything.
|
| It is mentioned that if you write to freed memory, that could
| lead to later callocs not returning zeroed memory, which shows
| they are relying on this.
| mcculley wrote:
| Yeah, if performance is the goal, zero is certainly faster. I
| have used 0xDEADBEEF to find both free-after-use and use-
| before-initialize bugs.
| rollulus wrote:
| The advantage of 0xDEADBEEF would be that it reduces the chance
| of software starting to rely on that value, compared to zero,
| isn't it?
| himinlomax wrote:
| Better for memory compression, at least.
| frogblast wrote:
| Malloc doesn't guarantee zero filling memory, but ObjC and
| Swift currently need to zero memory immediately after malloc
| returns it, and they both share C's malloc pool.
|
| This makes a lot more performance sense for those languages.
| mzs wrote:
| It's faster: https://community.arm.com/support-
| forums/f/architectures-and...
| bonzini wrote:
| Less likely to cause crashes, probably.
| mcculley wrote:
| I have used custom malloc()/free() implementations that do
| both just so I could find more crashes.
| Dwedit wrote:
| On Windows, deallocated blocks get filled with 0xFEFEFEFE. For
| 32-bit programs that aren't large-address-aware, this would
| basically have the same effect. Trying to dereference a pointer
| of that value will be an access violation.
| noobermin wrote:
| The fact that this is a problem is probably a sign that every OS
| should do this from the start so that apps won't be written
| that...rely on this behavior.
| dividuum wrote:
| It's not really an OS problem: it's the userland allocator that
| needs to implement this. So on Linux that would mostly be a
| glibc change to how malloc/free is implemented. The OS itself
| doesn't know whether or not a processes memory page is
| logically ,,in use". It only knows that once the process
| returns it (using for example munmap). But once you do that,
| any access crashes the process already.
| noobermin wrote:
| I hope you won't call me stallman but in my brain libc should
| be considered part of the OS, but yes, it would be clearer if
| I said "libc's should do it."
| spacecadet_ wrote:
| Apps aren't being written _on purpose_ to rely on the allocator
| doing nothing with freed memory because that's not in its
| interface, and this change doesn't actually do anything to stop
| apps from reading freed memory.
|
| There is no behavior that a program could legally rely on when
| reading freed memory. The assumption behind malloc/free is that
| freed allocations aren't used by the program anymore, so
| correct programs don't rely on reading freed memory at all and
| the allocator implementation is then free to do anything at all
| with the freed memory, it just turns out that the simplest
| behavior on the allocator side is to do nothing at all and just
| leave the freed memory as-is.
|
| The only thing this does when speaking of programs reading
| freed memory is that it breaks existing incorrect programs that
| just happened to work because of an implementation detail of
| the allocator, and then later someone will write another
| incorrect program that just happens to work because the
| allocator now zeroes out freed memory. To actually stop the
| problem of programs reading freed memory, the OS side would
| have to enforce the use of memory-safe languages which by
| design cannot access unused memory.
| ncmncm wrote:
| Writing random values to freed memory would mostly work, at
| some cost to performance.
|
| The memory could get allocated again before it is re-used,
| and whatever is put in it might be less trappy than a random
| value. And, of course, a random value might not trap.
|
| Better is not to do things that result in referring to dead
| memory: easy in modern C++, apparently difficult in C.
| noobermin wrote:
| To be very explicit, the "...rely" is me being facetious, I'm
| not really implying anyone actually relies on use after free!
| More like they lucked out on not catching it and shipped it
| anyway, hence the "rely" bit.
| tinus_hn wrote:
| The article does not actually claim this is a problem, it
| states the author thinks it will probably be a problem.
|
| I doubt this actually will be a problem for 99% of all apps,
| the 'but what about this essential software from 50 years ago'
| problem does not exist on Apple platforms because they
| routinely deprecate and then drop obsolete software without
| mercy.
|
| The only real problem I can imagine occurring is that this
| change uncovers dangerous security vulnerabilities that are a
| crash (so a denial of service) on those platforms but an
| exploit on others. But that's a problem for those other
| platforms to deal with.
___________________________________________________________________
(page generated 2022-09-22 23:01 UTC)