3

How can I detect if malloc fails in swift?

The end goal is to simply allocate the required amount of space, and if ios can not allocate it, report this elegantly to the user (instead of being terminated).

When I try the code below, the pointer is never nil and errno is always 0.

let pointer : UnsafeMutableRawPointer? = malloc(fileSize)
print("errno = \(errno)")
if (pointer == nil) {
    print("Malloc failed")
}
TJez
  • 1,969
  • 2
  • 19
  • 24
  • The pointer should be `nil` if `malloc` failed. Perhaps it never failed in your tests? – Martin R Sep 16 '17 at 18:50
  • 1
    What platform are you on? On Linux you might be the victim of the "optimistic memory allocation strategy": https://stackoverflow.com/a/7947888/1187415. – Martin R Sep 16 '17 at 18:52
  • Platform is ios. It's a deliberately large amount of memory, if I try to allocate the same size of memory through other means it fails. Perhaps the fail occurs during some initialisation later? – TJez Sep 16 '17 at 18:57
  • What "other means"? Please show the code so that we can compare the different methods. – Martin R Sep 16 '17 at 18:59
  • This will kill it: _array = UnsafeMutablePointer.allocate(capacity: _count) _array.initialize(to: initValue, count: _count) – TJez Sep 16 '17 at 19:17
  • Does the allocation fail or the initialization? – Martin R Sep 16 '17 at 19:19
  • 2
    According to https://www.mikeash.com/pyblog/friday-qa-2010-12-17-custom-object-allocators-in-objective-c.html#comment-6f3b9bf689eaf4ddec5473dd6dc1dce4, malloc on iOS uses the "optimistic memory allocation strategy" as well. That means that you can get a pointer, but *using* the memory later can crash. Using `calloc()` instead *might* be a solution. – Martin R Sep 16 '17 at 19:28
  • Thanks Martin, that's exactly what I am observing... which is why I am trying to move away from UnsafeMutableRawPointer's allocate. End goal is to simply allocate the required amount of space, and if it can not be allocated report it elegantly (instead of being terminated by ios). I'll update the question to reflect this. – TJez Sep 16 '17 at 21:54
  • 1
    As I recall the last time I went down this road, `calloc` doesn't help either because it fills with 0s, and the memory system is smart enough to leave all-0 pages unmapped. IIRC, even if your allocated block is writable, it doesn't mean that every page will be mappable when you try to write it, and so you could crash then. You can of course fill the memory with non-0 values to force it to be mapped, but that crashes if you're wrong. (So, Rob, how did you fix this? I never did.) – Rob Napier Sep 16 '17 at 22:10

2 Answers2

4

Why are you using malloc in Swift, at all?

let pointer = UnsafeMutablePointer<UInt8>.allocate(capacity: fileSize)

More to the point, under what circumstance does reading a file need you to manually allocate memory like this? Foundation provides APIs for reading files directly into Data.

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • 1
    Are you sure that `allocate()` doesn't suffer from the same problem? – OP said nothing about reading a file. There can be many reasons to allocate a memory buffer for whatever purposes. – Martin R Sep 16 '17 at 20:12
  • Because allocate gives no indication of failure either. – TJez Sep 16 '17 at 21:51
1

LLVM has an optimization which elides unused malloc calls. If your test code never actually needs the allocation, it will never be performed.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92