Home | History | Annotate | Download | only in docs
      1 # 32-bit ABI bugs
      2 
      3 ## 32-bit `off_t` and `_FILE_OFFSET_BITS=64`
      4 
      5 On 32-bit Android, `off_t` is a signed 32-bit integer. This limits functions
      6 that use `off_t` to working on files no larger than 2GiB.
      7 
      8 Android does not require the `_LARGEFILE_SOURCE` macro to be used to make
      9 `fseeko` and `ftello` available. Instead they're always available from API
     10 level 24 where they were introduced, and never available before then.
     11 
     12 Android also does not require the `_LARGEFILE64_SOURCE` macro to be used
     13 to make `off64_t` and corresponding functions such as `ftruncate64` available.
     14 Instead, whatever subset of those functions was available at your target API
     15 level will be visible.
     16 
     17 There are a couple of exceptions to note. Firstly, `off64_t` and the single
     18 function `lseek64` were available right from the beginning in API 3. Secondly,
     19 Android has always silently inserted `O_LARGEFILE` into any open call, so if
     20 all you need are functions like `read` that don't take/return `off_t`, large
     21 files have always worked.
     22 
     23 Android support for `_FILE_OFFSET_BITS=64` (which turns `off_t` into `off64_t`
     24 and replaces each `off_t` function with its `off64_t` counterpart, such as
     25 `lseek` in the source becoming `lseek64` at runtime) was added late. Even when
     26 it became available for the platform, it wasn't available from the NDK until
     27 r15. Before NDK r15, `_FILE_OFFSET_BITS=64` silently did nothing: all code
     28 compiled with that was actually using a 32-bit `off_t`. With a new enough NDK,
     29 the situation becomes complicated. If you're targeting an API before 21, almost
     30 all functions that take an `off_t` become unavailable. You've asked for their
     31 64-bit equivalents, and none of them (except `lseek`/`lseek64`) exist. As you
     32 increase your target API level, you'll have more and more of the functions
     33 available. API 12 adds some of the `<unistd.h>` functions, API 21 adds `mmap`,
     34 and by API 24 you have everything including `<stdio.h>`. See the
     35 [linker map](libc/libc.map.txt) for full details. Note also that in NDK r16 and
     36 later, if you're using Clang we'll inline an `mmap64` implementation in the
     37 headers when you target an API before 21 because it's an easy special case
     38 that's often needed. This means that code using `_FILE_OFFSET_BITS=64`
     39 and `mmap` (but no other functions that are unavailable at your target
     40 API level) will always compile.
     41 
     42 If your code stops compiling when you move to NDK r15 or later, removing every
     43 definition of `_FILE_OFFSET_BITS=64` will restore the behavior you used to have:
     44 you'll have a 32-bit `off_t` and use the 32-bit functions. Make sure you
     45 grep thoroughly in both your source and your build system: many people
     46 aren't aware that `_FILE_OFFSET_BITS` is set. You might also have to
     47 remove references to `__USE_FILE_OFFSET64` --- this is the internal
     48 flag that should never be set by user code but sometimes is (by zlib,
     49 for example). If you think you have removed these but your code still
     50 doesn't compile, you can insert this just before the line that's failing
     51 to double check:
     52 ```
     53 #if _FILE_OFFSET_BITS == 64
     54 #error "oops, file _FILE_OFFSET_BITS == 64"
     55 #elif defined(__USE_FILE_OFFSET64)
     56 #error "oops, __USE_FILE_OFFSET64 is defined"
     57 #endif
     58 ```
     59 
     60 In the 64-bit ABI, `off_t` is always 64-bit.
     61 
     62 For source compatibility, the names containing `64` are also available
     63 in the 64-bit ABI even though they're identical to the non-`64` names.
     64 
     65 
     66 ## `sigset_t` is too small for real-time signals
     67 
     68 On 32-bit Android, `sigset_t` is too small for ARM and x86 (but correct for
     69 MIPS). This means that there is no support for real-time signals in 32-bit
     70 code. Android P (API level 28) adds `sigset64_t` and a corresponding function
     71 for every function that takes a `sigset_t` (so `sigprocmask64` takes a
     72 `sigset64_t` where `sigprocmask` takes a `sigset_t`).
     73 
     74 On 32-bit Android, `struct sigaction` is also too small because it contains
     75 a `sigset_t`. We also offer a `struct sigaction64` and `sigaction64` function
     76 to work around this.
     77 
     78 In the 64-bit ABI, `sigset_t` is the correct size for every architecture.
     79 
     80 For source compatibility, the names containing `64` are also available
     81 in the 64-bit ABI even though they're identical to the non-`64` names.
     82 
     83 
     84 ## `time_t` is 32-bit
     85 
     86 On 32-bit Android, `time_t` is 32-bit. The header `<time64.h>` and type
     87 `time64_t` exist as a workaround, but the kernel interfaces exposed on 32-bit
     88 Android all use the 32-bit `time_t`.
     89 
     90 In the 64-bit ABI, `time_t` is 64-bit.
     91 
     92 
     93 ## `pthread_mutex_t` is too small for large pids
     94 
     95 This doesn't generally affect Android devices, because on devices
     96 `/proc/sys/kernel/pid_max` is usually too small to hit our 16-bit limit,
     97 but 32-bit bionic's `pthread_mutex` is a total of 32 bits, leaving just
     98 16 bits for the owner thread id. This means bionic isn't able to support
     99 mutexes for tids that don't fit in 16 bits. This typically manifests as
    100 a hang in `pthread_mutex_lock` if the libc startup code doesn't detect
    101 this condition and abort.
    102