[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)