tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

getline_interposer.cpp (2615B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6 * Interposing getline because of
      7 * https://bugzilla.mozilla.org/show_bug.cgi?id=914190
      8 */
      9 
     10 #ifdef __ANDROID__
     11 
     12 #  include <cstdlib>
     13 #  include <cstdio>
     14 #  include <cerrno>
     15 
     16 #  include <limits>
     17 
     18 namespace {
     19 
     20 // RAII on file locking.
     21 class FileLocker {
     22  FILE* stream;
     23 
     24 public:
     25  explicit FileLocker(FILE* stream) : stream(stream) { flockfile(stream); }
     26  ~FileLocker() { funlockfile(stream); }
     27 };
     28 
     29 ssize_t internal_getdelim(char** __restrict lineptr, size_t* __restrict n,
     30                          int delim, FILE* __restrict stream) {
     31  constexpr size_t n_default = 64;
     32  constexpr size_t n_max =
     33      std::numeric_limits<ssize_t>::max() < std::numeric_limits<size_t>::max()
     34          ? (size_t)std::numeric_limits<ssize_t>::max() + 1
     35          : std::numeric_limits<size_t>::max();
     36  constexpr size_t n_limit = 2 * ((n_max - 1) / 3);
     37 
     38  if (!lineptr || !n || !stream) {
     39    errno = EINVAL;
     40    return -1;
     41  }
     42 
     43  // Lock the file so that we can us unlocked getc in the inner loop.
     44  FileLocker fl(stream);
     45 
     46  if (!*lineptr || *n == 0) {
     47    *n = n_default;
     48    if (auto* new_lineptr = reinterpret_cast<char*>(realloc(*lineptr, *n))) {
     49      *lineptr = new_lineptr;
     50    } else {
     51      errno = ENOMEM;
     52      return -1;
     53    }
     54  }
     55 
     56  ssize_t result;
     57  size_t cur_len = 0;
     58 
     59  while (true) {
     60    // Retrieve an extra char.
     61    int i = getc_unlocked(stream);
     62    if (i == EOF) {
     63      result = -1;
     64      break;
     65    }
     66 
     67    // Eventually grow the buffer.
     68    if (cur_len + 1 >= *n) {
     69      size_t needed = *n >= n_limit ? n_max : 3 * *n / 2 + 1;
     70 
     71      if (cur_len + 1 >= needed) {
     72        errno = EOVERFLOW;
     73        return -1;
     74      }
     75 
     76      if (auto* new_lineptr = (char*)realloc(*lineptr, needed)) {
     77        *lineptr = new_lineptr;
     78      } else {
     79        errno = ENOMEM;
     80        return -1;
     81      }
     82      *n = needed;
     83    }
     84 
     85    (*lineptr)[cur_len] = i;
     86    cur_len++;
     87 
     88    if (i == delim) break;
     89  }
     90  (*lineptr)[cur_len] = '\0';
     91  return cur_len ? cur_len : result;
     92 }
     93 
     94 }  // namespace
     95 
     96 extern "C" {
     97 
     98 MFBT_API ssize_t getline(char** __restrict lineptr, size_t* __restrict n,
     99                         FILE* __restrict stream) {
    100  return internal_getdelim(lineptr, n, '\n', stream);
    101 }
    102 
    103 MFBT_API ssize_t getdelim(char** __restrict lineptr, size_t* __restrict n,
    104                          int delim, FILE* __restrict stream) {
    105  return internal_getdelim(lineptr, n, delim, stream);
    106 }
    107 
    108 }  // extern "C"
    109 
    110 #endif