_Z8mem_openPKhm:
   55|      1|TSK_IMG_INFO *mem_open(const uint8_t *data, size_t size) {
   56|      1|  IMG_MEM_INFO *inmemory_img =
   57|      1|      reinterpret_cast<IMG_MEM_INFO *>(malloc(sizeof(IMG_MEM_INFO)));
   58|      1|  TSK_IMG_INFO *img;
   59|      1|  if (inmemory_img == nullptr) {
  ------------------
  |  Branch (59:7): [True: 0, False: 1]
  ------------------
   60|      0|    return nullptr;
   61|      0|  }
   62|      1|  img = reinterpret_cast<TSK_IMG_INFO *>(inmemory_img);
   63|      1|  img->itype = TSK_IMG_TYPE_RAW;
   64|      1|  img->read = mem_read;
   65|      1|  img->close = mem_close;
   66|      1|  img->imgstat = mem_imgstat;
   67|      1|  img->size = size;
   68|      1|  img->sector_size = 512;
   69|      1|  tsk_init_lock(&(img->cache_lock));
   70|      1|  inmemory_img->data = data;
   71|      1|  inmemory_img->size = size;
   72|      1|  return img;
   73|      1|}
sleuthkit_fls_apfs_fuzzer.cc:_ZL8mem_readP12TSK_IMG_INFOlPcm:
   30|      1|                        size_t len) {
   31|      1|  IMG_MEM_INFO *mem_info = reinterpret_cast<IMG_MEM_INFO *>(img_info);
   32|       |  // Bounds-checking exists in the real drivers.
   33|      1|  if (offset > mem_info->size) {
  ------------------
  |  Branch (33:7): [True: 0, False: 1]
  ------------------
   34|      0|    return -1;
   35|      0|  }
   36|      1|  ssize_t read_len = len;
   37|      1|  if (offset + len > mem_info->size) {
  ------------------
  |  Branch (37:7): [True: 0, False: 1]
  ------------------
   38|      0|    read_len = mem_info->size - offset;
   39|      0|  }
   40|      1|  if (memcpy(buf, mem_info->data + offset, read_len) == nullptr) {
  ------------------
  |  Branch (40:7): [True: 0, False: 1]
  ------------------
   41|      0|    return -1;
   42|      1|  } else {
   43|      1|    return read_len;
   44|      1|  }
   45|      1|}
sleuthkit_fls_apfs_fuzzer.cc:_ZL9mem_closeP12TSK_IMG_INFO:
   47|      1|static void mem_close(TSK_IMG_INFO *img_info) {
   48|      1|  IMG_MEM_INFO *mem_info = reinterpret_cast<IMG_MEM_INFO *>(img_info);
   49|      1|  tsk_deinit_lock(&(img_info->cache_lock));
   50|      1|  free(mem_info);
   51|      1|}

_Z14hexDigitToCharc:
   85|    256|{
   86|    256|  if (ch > 47 && ch < 58)
  ------------------
  |  Branch (86:7): [True: 256, False: 0]
  |  Branch (86:18): [True: 148, False: 108]
  ------------------
   87|    148|    return ch - 48;
   88|       |
   89|    108|  if (ch > 96 && ch < 103)
  ------------------
  |  Branch (89:7): [True: 108, False: 0]
  |  Branch (89:18): [True: 108, False: 0]
  ------------------
   90|    108|    return ch - 87;
   91|       |
   92|      0|  if (ch > 64 && ch < 71)
  ------------------
  |  Branch (92:7): [True: 0, False: 0]
  |  Branch (92:18): [True: 0, False: 0]
  ------------------
   93|      0|    return ch - 55;
   94|       |
   95|      0|  return 0;
   96|      0|}
_Z13hexPairToCharcc:
  100|    128|{
  101|    128|  return hexDigitToChar(a) * 16 + hexDigitToChar(b);
  102|    128|}
_ZN7TSKGuidC2ERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE:
  106|      8|{
  107|      8|  _bytes.clear();
  108|       |
  109|      8|  char charOne, charTwo;
  110|      8|  bool lookingForFirstChar = true;
  111|       |
  112|       |  // for (const char &ch : fromString) C++ 11 CODE CHANGED FOR TSK
  113|    296|  for (std::string::const_iterator it = fromString.begin(); it != fromString.end(); ++it)
  ------------------
  |  Branch (113:61): [True: 288, False: 8]
  ------------------
  114|    288|  {
  115|    288|    char ch = *it;
  116|    288|    if (ch == '-')
  ------------------
  |  Branch (116:9): [True: 32, False: 256]
  ------------------
  117|     32|      continue;
  118|       |
  119|    256|    if (lookingForFirstChar)
  ------------------
  |  Branch (119:9): [True: 128, False: 128]
  ------------------
  120|    128|    {
  121|    128|      charOne = ch;
  122|    128|      lookingForFirstChar = false;
  123|    128|    }
  124|    128|    else
  125|    128|    {
  126|    128|      charTwo = ch;
  127|    128|      unsigned char byte = hexPairToChar(charOne, charTwo);
  128|    128|      _bytes.push_back(byte);
  129|    128|      lookingForFirstChar = true;
  130|    128|    }
  131|    256|  }
  132|       |
  133|      8|}
_ZN7TSKGuidC2Ev:
  137|      1|{
  138|      1|  _bytes = vector<unsigned char>(16, 0);
  139|      1|}

tsk_error_get_info:
  148|      3|{
  149|      3|    TSK_ERROR_INFO *ptr = NULL;
  150|      3|    (void) pthread_once(&pt_tls_key_once, make_pt_tls_key);
  151|      3|    if ((ptr = (TSK_ERROR_INFO *) pthread_getspecific(pt_tls_key)) == 0) {
  ------------------
  |  Branch (151:9): [True: 1, False: 2]
  ------------------
  152|       |        // Under high memory pressure malloc will return NULL.
  153|      1|        ptr = (TSK_ERROR_INFO *) malloc(sizeof(TSK_ERROR_INFO));
  154|       |
  155|      1|        if( ptr != NULL ) {
  ------------------
  |  Branch (155:13): [True: 1, False: 0]
  ------------------
  156|      1|            ptr->t_errno = 0;
  157|      1|            ptr->errstr[0] = 0;
  158|      1|            ptr->errstr2[0] = 0;
  159|      1|        }
  160|      1|        (void) pthread_setspecific(pt_tls_key, ptr);
  161|      1|    }
  162|      3|    return ptr;
  163|      3|}
tsk_error_set_errno:
  308|      1|{
  309|      1|    tsk_error_get_info()->t_errno = t_errno;
  310|      1|}
tsk_error_set_errstr:
  332|      1|{
  333|      1|    va_list args;
  334|      1|    va_start(args, format);
  335|      1|    vsnprintf(tsk_error_get_info()->errstr, TSK_ERROR_STRING_MAX_LENGTH,
  ------------------
  |  |   67|      1|#define TSK_ERROR_STRING_MAX_LENGTH 1024
  ------------------
  336|      1|        format, args);
  337|      1|    va_end(args);
  338|      1|}
tsk_error_reset:
  444|      1|{
  445|      1|    TSK_ERROR_INFO *info = tsk_error_get_info();
  446|       |
  447|      1|    if( info != NULL ) {
  ------------------
  |  Branch (447:9): [True: 1, False: 0]
  ------------------
  448|      1|       info->t_errno = 0;
  449|      1|       info->errstr[0] = 0;
  450|      1|       info->errstr2[0] = 0;
  451|      1|       info->errstr_print[0] = 0;
  452|      1|    }
  453|      1|}
tsk_error.c:make_pt_tls_key:
  142|      1|{
  143|      1|    (void) pthread_key_create(&pt_tls_key, free_error_info);
  144|      1|}

tsk_init_lock:
   46|      1|{
   47|      1|    pthread_mutexattr_t attr;
   48|      1|    pthread_mutexattr_init(&attr);
   49|       |
   50|       |    // Locks on Linux are not recursive (unlike on Windows), so things
   51|       |    // will hang if the current thread tries to take the lock again.
   52|       |    // While debugging, it's sometimes useful to call
   53|       |    //
   54|       |    //  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
   55|       |    //
   56|       |    // which will provoke an immediate error rather than a hang.
   57|       |    //
   58|       |    // PTHREAD_MUTEX_ERRORCHECK is not defined by default on Linux,
   59|       |    // but it is portable if you have the right_XOPEN_SOURCE settings.
   60|       |    // However, that macro affects the availability of other features
   61|       |    // like BSD-style u_int types used in afflib.
   62|       |    // PTHREAD_MUTEX_ERRORCHECK -is- available by default on Mac.
   63|       |    //
   64|       |    // PTHREAD_MUTEX_ERRORCHECK_NP is the Linux/gcc non-portable
   65|       |    // equivalent which does not require _XOPEN_SOURCE.
   66|       |    //
   67|       |    // Other interesting attributes are PTHREAD_MUTEX_RECURSIVE (and
   68|       |    // PTHREAD_MUTEX_RECURSIVE_NP).  We avoided those out of portability
   69|       |    // concerns with the _XOPEN_SOURCE settings.
   70|       |
   71|      1|    int e = pthread_mutex_init(&lock->mutex, &attr);
   72|      1|    pthread_mutexattr_destroy(&attr);
   73|      1|    if (e != 0) {
  ------------------
  |  Branch (73:9): [True: 0, False: 1]
  ------------------
   74|      0|        fprintf(stderr, "tsk_init_lock: thread_mutex_init failed %d\n", e);
   75|      0|        assert(0);
   76|      0|    }
   77|      1|}
tsk_deinit_lock:
   81|      2|{
   82|      2|    pthread_mutex_destroy(&lock->mutex);
   83|      2|}
tsk_take_lock:
   87|      1|{
   88|      1|    int e = pthread_mutex_lock(&lock->mutex);
   89|      1|    if (e != 0) {
  ------------------
  |  Branch (89:9): [True: 0, False: 1]
  ------------------
   90|      0|        fprintf(stderr, "tsk_take_lock: thread_mutex_lock failed %d\n", e);
   91|      0|        assert(0);
   92|      0|    }
   93|      1|}
tsk_release_lock:
   97|      1|{
   98|      1|    int e = pthread_mutex_unlock(&lock->mutex);
   99|      1|    if (e != 0) {
  ------------------
  |  Branch (99:9): [True: 0, False: 1]
  ------------------
  100|      0|        fprintf(stderr,
  101|      0|            "tsk_release_lock: thread_mutex_unlock failed %d\n", e);
  102|      0|        assert(0);
  103|      0|    }
  104|      1|}

_ZN9APFSBlockC2ERK8APFSPoolm:
  130|      1|    : _storage{}, _pool{pool}, _block_num{block_num} {
  131|      1|  const auto sz =
  132|      1|      pool.read(block_num * APFS_BLOCK_SIZE, _storage.data(), APFS_BLOCK_SIZE);
  ------------------
  |  |   26|      1|#define APFS_BLOCK_SIZE 4096
  ------------------
                    pool.read(block_num * APFS_BLOCK_SIZE, _storage.data(), APFS_BLOCK_SIZE);
  ------------------
  |  |   26|      1|#define APFS_BLOCK_SIZE 4096
  ------------------
  133|      1|  if (sz != APFS_BLOCK_SIZE) {
  ------------------
  |  |   26|      1|#define APFS_BLOCK_SIZE 4096
  ------------------
  |  Branch (133:7): [True: 0, False: 1]
  ------------------
  134|      0|    throw std::runtime_error("could not read APFSBlock");
  135|      0|  }
  136|      1|}
_ZN14APFSSuperblockC2ERK8APFSPoolm:
  196|      1|    : APFSObject(pool, block_num), _spaceman{} {
  197|      1|  if (obj_type() != APFS_OBJ_TYPE_SUPERBLOCK) {
  ------------------
  |  Branch (197:7): [True: 1, False: 0]
  ------------------
  198|      1|    throw std::runtime_error("APFSSuperblock: invalid object type");
  199|      1|  }
  200|       |
  201|      0|  if (sb()->magic != APFS_NXSUPERBLOCK_MAGIC) {
  ------------------
  |  |   29|      0|#define APFS_NXSUPERBLOCK_MAGIC 0x4253584E  // NXSB
  ------------------
  |  Branch (201:7): [True: 0, False: 0]
  ------------------
  202|      0|    throw std::runtime_error("APFSSuperblock: invalid magic");
  203|      0|  }
  204|       |
  205|      0|  if (bit_is_set(sb()->incompatible_features, APFS_NXSB_INCOMPAT_VERSION1)) {
  ------------------
  |  |  117|      0|#define APFS_NXSB_INCOMPAT_VERSION1 0x0000000000000001ULL
  ------------------
  |  Branch (205:7): [True: 0, False: 0]
  ------------------
  206|      0|    throw std::runtime_error(
  207|      0|        "APFSSuperblock: Pre-release versions of APFS are not supported");
  208|      0|  }
  209|       |
  210|      0|  if (bit_is_set(sb()->incompatible_features, APFS_NXSB_INCOMPAT_FUSION)) {
  ------------------
  |  |  119|      0|#define APFS_NXSB_INCOMPAT_FUSION 0x0000000000000100ULL
  ------------------
  |  Branch (210:7): [True: 0, False: 0]
  ------------------
  211|      0|    if (tsk_verbose) {
  ------------------
  |  Branch (211:9): [True: 0, False: 0]
  ------------------
  212|      0|      tsk_fprintf(stderr,
  213|      0|                  "WARNING: APFS fusion drives may not be fully supported\n");
  214|      0|    }
  215|      0|  }
  216|       |
  217|      0|  if (block_size() != APFS_BLOCK_SIZE) {
  ------------------
  |  |   26|      0|#define APFS_BLOCK_SIZE 4096
  ------------------
  |  Branch (217:7): [True: 0, False: 0]
  ------------------
  218|      0|    throw std::runtime_error(
  219|      0|        "APFSSuperblock: invalid or unsupported block size");
  220|      0|  }
  221|      0|}

tsk_img_read:
   60|      1|{
   61|      1|#define CACHE_AGE   1000
   62|      1|    ssize_t read_count = 0;
   63|      1|    int cache_index = 0;
   64|      1|    int cache_next = 0;         // index to lowest age cache (to use next)
   65|      1|    size_t len2 = 0;
   66|       |
   67|      1|    if (a_img_info == NULL) {
  ------------------
  |  Branch (67:9): [True: 0, False: 1]
  ------------------
   68|      0|        tsk_error_reset();
   69|      0|        tsk_error_set_errno(TSK_ERR_IMG_ARG);
  ------------------
  |  |  320|      0|#define TSK_ERR_IMG_ARG	    (TSK_ERR_IMG | 9)
  |  |  ------------------
  |  |  |  |  299|      0|#define TSK_ERR_IMG	0x02000000
  |  |  ------------------
  ------------------
   70|      0|        tsk_error_set_errstr("tsk_img_read: a_img_info: NULL");
   71|      0|        return -1;
   72|      0|    }
   73|       |
   74|       |    // Do not allow a_buf to be NULL.
   75|      1|    if (a_buf == NULL) {
  ------------------
  |  Branch (75:9): [True: 0, False: 1]
  ------------------
   76|      0|        tsk_error_reset();
   77|      0|        tsk_error_set_errno(TSK_ERR_IMG_ARG);
  ------------------
  |  |  320|      0|#define TSK_ERR_IMG_ARG	    (TSK_ERR_IMG | 9)
  |  |  ------------------
  |  |  |  |  299|      0|#define TSK_ERR_IMG	0x02000000
  |  |  ------------------
  ------------------
   78|      0|        tsk_error_set_errstr("tsk_img_read: a_buf: NULL");
   79|      0|        return -1;
   80|      0|    }
   81|       |
   82|       |    // The function cannot handle negative offsets.
   83|      1|    if (a_off < 0) {
  ------------------
  |  Branch (83:9): [True: 0, False: 1]
  ------------------
   84|      0|        tsk_error_reset();
   85|      0|        tsk_error_set_errno(TSK_ERR_IMG_ARG);
  ------------------
  |  |  320|      0|#define TSK_ERR_IMG_ARG	    (TSK_ERR_IMG | 9)
  |  |  ------------------
  |  |  |  |  299|      0|#define TSK_ERR_IMG	0x02000000
  |  |  ------------------
  ------------------
   86|      0|        tsk_error_set_errstr("tsk_img_read: a_off: %" PRIdOFF, a_off);
  ------------------
  |  |  269|      0|#define PRIdOFF		PRId64
  ------------------
   87|      0|        return -1;
   88|      0|    }
   89|       |
   90|       |    // Protect a_off against overflowing when a_len is added since TSK_OFF_T
   91|       |    // maps to an int64 we prefer it over size_t although likely checking
   92|       |    // for ( a_len > SSIZE_MAX ) is better but the code does not seem to
   93|       |    // use that approach.
   94|       |
   95|      1|    if ((TSK_OFF_T) a_len < 0) {
  ------------------
  |  Branch (95:9): [True: 0, False: 1]
  ------------------
   96|      0|        tsk_error_reset();
   97|      0|        tsk_error_set_errno(TSK_ERR_IMG_ARG);
  ------------------
  |  |  320|      0|#define TSK_ERR_IMG_ARG	    (TSK_ERR_IMG | 9)
  |  |  ------------------
  |  |  |  |  299|      0|#define TSK_ERR_IMG	0x02000000
  |  |  ------------------
  ------------------
   98|      0|        tsk_error_set_errstr("tsk_img_read: a_len: %zd", a_len);
   99|      0|        return -1;
  100|      0|    }
  101|       |
  102|       |    /* cache_lock is used for both the cache in IMG_INFO and 
  103|       |     * the shared variables in the img type specific INFO structs.
  104|       |     * grab it now so that it is held before any reads.
  105|       |     */
  106|      1|    tsk_take_lock(&(a_img_info->cache_lock));
  107|       |
  108|       |    // if they ask for more than the cache length, skip the cache
  109|      1|    if ((a_len + (a_off % 512)) > TSK_IMG_INFO_CACHE_LEN) {
  ------------------
  |  |   85|      1|#define TSK_IMG_INFO_CACHE_LEN  65536
  ------------------
  |  Branch (109:9): [True: 0, False: 1]
  ------------------
  110|      0|        read_count = tsk_img_read_no_cache(a_img_info, a_off, a_buf, a_len);
  111|      0|        tsk_release_lock(&(a_img_info->cache_lock));
  112|      0|        return read_count;
  113|      0|    }
  114|       |
  115|       |    // TODO: why not just return 0 here (and be POSIX compliant)?
  116|       |    // and why not check earlier for this condition?
  117|      1|    if (a_off >= a_img_info->size) {
  ------------------
  |  Branch (117:9): [True: 0, False: 1]
  ------------------
  118|      0|        tsk_release_lock(&(a_img_info->cache_lock));
  119|      0|        tsk_error_reset();
  120|      0|        tsk_error_set_errno(TSK_ERR_IMG_READ_OFF);
  ------------------
  |  |  319|      0|#define TSK_ERR_IMG_READ_OFF	(TSK_ERR_IMG | 8)
  |  |  ------------------
  |  |  |  |  299|      0|#define TSK_ERR_IMG	0x02000000
  |  |  ------------------
  ------------------
  121|      0|        tsk_error_set_errstr("tsk_img_read - %" PRIdOFF, a_off);
  ------------------
  |  |  269|      0|#define PRIdOFF		PRId64
  ------------------
  122|      0|        return -1;
  123|      0|    }
  124|       |
  125|       |    /* See if the requested length is going to be too long.
  126|       |     * we'll use this length when checking the cache. */
  127|      1|    len2 = a_len;
  128|       |
  129|       |    // Protect against INT64_MAX + INT64_MAX > value
  130|      1|    if (((TSK_OFF_T) len2 > a_img_info->size)
  ------------------
  |  Branch (130:9): [True: 0, False: 1]
  ------------------
  131|      1|        || (a_off >= (a_img_info->size - (TSK_OFF_T)len2))) {
  ------------------
  |  Branch (131:12): [True: 0, False: 1]
  ------------------
  132|      0|        len2 = (size_t) (a_img_info->size - a_off);
  133|      0|    }
  134|       |
  135|       |    // check if it is in the cache
  136|      1|    for (cache_index = 0;
  137|     33|        cache_index < TSK_IMG_INFO_CACHE_NUM; cache_index++) {
  ------------------
  |  |   84|     33|#define TSK_IMG_INFO_CACHE_NUM  32
  ------------------
  |  Branch (137:9): [True: 32, False: 1]
  ------------------
  138|       |
  139|       |        // Look into the in-use cache entries
  140|     32|        if (a_img_info->cache_len[cache_index] > 0) {
  ------------------
  |  Branch (140:13): [True: 0, False: 32]
  ------------------
  141|       |
  142|       |            // the read_count check makes sure we don't go back in after data was read
  143|      0|            if ((read_count == 0)
  ------------------
  |  Branch (143:17): [True: 0, False: 0]
  ------------------
  144|      0|                && (a_img_info->cache_off[cache_index] <= a_off)
  ------------------
  |  Branch (144:20): [True: 0, False: 0]
  ------------------
  145|      0|                && (a_img_info->cache_off[cache_index] +
  ------------------
  |  Branch (145:20): [True: 0, False: 0]
  ------------------
  146|      0|                    a_img_info->cache_len[cache_index] >= a_off + len2)) {
  147|       |
  148|       |                /*
  149|       |                   if (tsk_verbose)
  150|       |                   fprintf(stderr,
  151|       |                   "tsk_img_read: Read found in cache %d\n",  cache_index );
  152|       |                 */
  153|       |
  154|       |                // We found it...
  155|      0|                memcpy(a_buf,
  156|      0|                    &a_img_info->cache[cache_index][a_off -
  157|      0|                        a_img_info->cache_off[cache_index]], len2);
  158|      0|                read_count = (ssize_t) len2;
  159|       |
  160|       |                // reset its "age" since it was useful
  161|      0|                a_img_info->cache_age[cache_index] = CACHE_AGE;
  ------------------
  |  |   61|      0|#define CACHE_AGE   1000
  ------------------
  162|       |
  163|       |                // we don't break out of the loop so that we update all ages
  164|      0|            }
  165|      0|            else {
  166|       |                /* decrease its "age" since it was not useful.
  167|       |                 * We don't let used ones go below 1 so that they are not
  168|       |                 * confused with entries that have never been used. */
  169|      0|                a_img_info->cache_age[cache_index]--;
  170|       |
  171|       |                // see if this is the most eligible replacement
  172|      0|                if ((a_img_info->cache_len[cache_next] > 0)
  ------------------
  |  Branch (172:21): [True: 0, False: 0]
  ------------------
  173|      0|                    && (a_img_info->cache_age[cache_index] <
  ------------------
  |  Branch (173:24): [True: 0, False: 0]
  ------------------
  174|      0|                        a_img_info->cache_age[cache_next]))
  175|      0|                    cache_next = cache_index;
  176|      0|            }
  177|      0|        }
  178|     32|        else {
  179|     32|            cache_next = cache_index;
  180|     32|        }
  181|     32|    }
  182|       |
  183|       |    // if we didn't find it, then load it into the cache_next entry
  184|      1|    if (read_count == 0) {
  ------------------
  |  Branch (184:9): [True: 1, False: 0]
  ------------------
  185|      1|        size_t read_size = 0;
  186|       |
  187|       |        // round the offset down to a sector boundary
  188|      1|        a_img_info->cache_off[cache_next] = (a_off / 512) * 512;
  189|       |
  190|       |        /*
  191|       |           if (tsk_verbose)
  192|       |           fprintf(stderr,
  193|       |           "tsk_img_read: Loading data into cache %d (%" PRIdOFF
  194|       |           ")\n", cache_next, a_img_info->cache_off[cache_next]);
  195|       |         */
  196|       |
  197|       |        // Read a full cache block or the remaining data.
  198|      1|        read_size = TSK_IMG_INFO_CACHE_LEN;
  ------------------
  |  |   85|      1|#define TSK_IMG_INFO_CACHE_LEN  65536
  ------------------
  199|       |
  200|      1|        if ((a_img_info->cache_off[cache_next] + (TSK_OFF_T)read_size) >
  ------------------
  |  Branch (200:13): [True: 0, False: 1]
  ------------------
  201|      1|            a_img_info->size) {
  202|      0|            read_size =
  203|      0|                (size_t) (a_img_info->size -
  204|      0|                a_img_info->cache_off[cache_next]);
  205|      0|        }
  206|       |
  207|      1|        read_count = a_img_info->read(a_img_info,
  208|      1|            a_img_info->cache_off[cache_next],
  209|      1|            a_img_info->cache[cache_next], read_size);
  210|       |
  211|       |        // if no error, then set the variables and copy the data
  212|       |        // Although a read_count of -1 indicates an error,
  213|       |        // since read_count is used in the calculation it may not be negative.
  214|       |        // Also it does not make sense to copy data when the read_count is 0.
  215|      1|        if (read_count > 0) {
  ------------------
  |  Branch (215:13): [True: 1, False: 0]
  ------------------
  216|       |
  217|      1|            TSK_OFF_T rel_off = 0;
  218|      1|            a_img_info->cache_age[cache_next] = CACHE_AGE;
  ------------------
  |  |   61|      1|#define CACHE_AGE   1000
  ------------------
  219|      1|            a_img_info->cache_len[cache_next] = read_count;
  220|       |
  221|       |            // Determine the offset relative to the start of the cached data.
  222|      1|            rel_off = a_off - a_img_info->cache_off[cache_next];
  223|       |
  224|       |            // Make sure we were able to read sufficient data into the cache.
  225|      1|            if (rel_off > (TSK_OFF_T) read_count) {
  ------------------
  |  Branch (225:17): [True: 0, False: 1]
  ------------------
  226|      0|                len2 = 0;
  227|      0|            }
  228|       |            // Make sure not to copy more than is available in the cache.
  229|      1|            else if ((rel_off + (TSK_OFF_T) len2) > (TSK_OFF_T) read_count) {
  ------------------
  |  Branch (229:22): [True: 0, False: 1]
  ------------------
  230|      0|                len2 = (size_t) (read_count - rel_off);
  231|      0|            }
  232|       |            // Only copy data when we have something to copy.
  233|      1|            if (len2 > 0) {
  ------------------
  |  Branch (233:17): [True: 1, False: 0]
  ------------------
  234|      1|                memcpy(a_buf, &(a_img_info->cache[cache_next][rel_off]), len2);
  235|      1|            }
  236|      1|            read_count = (ssize_t) len2;
  237|      1|        }
  238|      0|        else {
  239|      0|            a_img_info->cache_len[cache_next] = 0;
  240|      0|            a_img_info->cache_age[cache_next] = 0;
  241|      0|            a_img_info->cache_off[cache_next] = 0;
  242|       |
  243|       |            // Something went wrong so let's try skipping the cache
  244|      0|            read_count = tsk_img_read_no_cache(a_img_info, a_off, a_buf, a_len);
  245|      0|        }
  246|      1|    }
  247|       |
  248|      1|    tsk_release_lock(&(a_img_info->cache_lock));
  249|      1|    return read_count;
  250|      1|}

tsk_img_close:
  573|      1|{
  574|      1|    if (a_img_info == NULL) {
  ------------------
  |  Branch (574:9): [True: 0, False: 1]
  ------------------
  575|      0|        return;
  576|      0|    }
  577|      1|    tsk_deinit_lock(&(a_img_info->cache_lock));
  578|      1|    a_img_info->close(a_img_info);
  579|      1|}

_ZNK10APFSObject3objEv:
   42|      1|  inline const apfs_obj_header *obj() const noexcept {
   43|      1|    return reinterpret_cast<const apfs_obj_header *>(_storage.data());
   44|      1|  }
_ZNK10APFSObject8obj_typeEv:
   52|      1|  inline APFS_OBJ_TYPE_ENUM obj_type() const noexcept {
   53|      1|    return APFS_OBJ_TYPE_ENUM(obj()->type);
   54|      1|  }

_ZN9APFSBlockD2Ev:
   48|      1|  virtual ~APFSBlock() = default;

_ZN8APFSPoolC2EONSt3__16vectorINS0_4pairIKP12TSK_IMG_INFOKlEENS0_9allocatorIS7_EEEEm:
   21|      1|      _nx_block_num{nx_block_num} {
   22|      1|  if (_members.size() != 1) {
  ------------------
  |  Branch (22:7): [True: 0, False: 1]
  ------------------
   23|      0|    throw std::runtime_error(
   24|      0|        "Only single physical store APFS pools are currently supported");
   25|      0|  }
   26|       |
   27|       |  // If we're scanning for the latest NXSB then we need to start with the
   28|       |  // last known good NXSB first
   29|      1|  if (_nx_block_num == APFS_POOL_NX_BLOCK_LATEST) {
  ------------------
  |  |   18|      1|#define APFS_POOL_NX_BLOCK_LATEST 0xFFFFFFFFFFFFFFFFULL
  ------------------
  |  Branch (29:7): [True: 1, False: 0]
  ------------------
   30|      1|    _nx_block_num = APFS_POOL_NX_BLOCK_LAST_KNOWN_GOOD;
  ------------------
  |  |   17|      1|#define APFS_POOL_NX_BLOCK_LAST_KNOWN_GOOD 0ULL
  ------------------
   31|      1|  }
   32|       |
   33|      1|  std::tie(_img, _offset) = _members[0];
   34|       |
   35|      1|  auto nxsb = nx(true);
   36|       |
   37|       |  // Update the base members
   38|      1|  _uuid = nxsb->uuid();
   39|      1|  _block_size = nxsb->block_size();
   40|      1|  _dev_block_size = _img->sector_size;
   41|      1|  _num_blocks = nxsb->num_blocks();
   42|       |
   43|       |  // Check to see if we need to scan for a newer pool
   44|      1|  if (nx_block_num == APFS_POOL_NX_BLOCK_LATEST) {
  ------------------
  |  |   18|      1|#define APFS_POOL_NX_BLOCK_LATEST 0xFFFFFFFFFFFFFFFFULL
  ------------------
  |  Branch (44:7): [True: 0, False: 1]
  ------------------
   45|      0|    const auto versions = known_versions();
   46|       |
   47|      0|    if (versions.empty()) {
  ------------------
  |  Branch (47:9): [True: 0, False: 0]
  ------------------
   48|      0|      _nx_block_num = APFS_POOL_NX_BLOCK_LAST_KNOWN_GOOD;
  ------------------
  |  |   17|      0|#define APFS_POOL_NX_BLOCK_LAST_KNOWN_GOOD 0ULL
  ------------------
   49|      0|      if (tsk_verbose) {
  ------------------
  |  Branch (49:11): [True: 0, False: 0]
  ------------------
   50|      0|        tsk_fprintf(stderr,
   51|      0|                    "APFSPool: No checkpoint superblocks found.  Attempting to "
   52|      0|                    "fall back to last known good superblock\n");
   53|      0|      }
   54|      0|    } else {
   55|      0|      const auto highest = std::max_element(
   56|      0|          versions.begin(), versions.end(),
   57|      0|          [](const auto& a, const auto& b) { return a.xid < b.xid; });
   58|       |
   59|       |      // No need to do anything, we're already the highest version
   60|      0|      if (highest->xid != nxsb->xid()) {
  ------------------
  |  Branch (60:11): [True: 0, False: 0]
  ------------------
   61|      0|        _nx_block_num = highest->nx_block_num;
   62|       |
   63|      0|        try {
   64|      0|          nxsb = nx(true);
   65|      0|        } catch (const std::runtime_error&) {
   66|       |          // Fallback to last known good block if the latest block is not valid
   67|      0|          _nx_block_num = APFS_POOL_NX_BLOCK_LAST_KNOWN_GOOD;
  ------------------
  |  |   17|      0|#define APFS_POOL_NX_BLOCK_LAST_KNOWN_GOOD 0ULL
  ------------------
   68|      0|          nxsb = nx(true);
   69|      0|        }
   70|      0|      }
   71|      0|    }
   72|      0|  }
   73|       |
   74|      1|  _vol_blocks = nxsb->volume_blocks();
   75|      1|  _num_vols = static_cast<int>(_vol_blocks.size());
   76|       |
   77|       |  // If the software crypto bit is not set, then either hardware crypto is used
   78|       |  // or there are no volumes that are encrypted.
   79|      1|  if (bit_is_set(nxsb->sb()->flags, APFS_NXSB_FLAGS_CRYPTO_SW) == false) {
  ------------------
  |  |  124|      1|#define APFS_NXSB_FLAGS_CRYPTO_SW 0x00000004LL
  ------------------
  |  Branch (79:7): [True: 0, False: 1]
  ------------------
   80|       |    // We need to check each volume to determine if any of them have encryption
   81|       |    // enabled.
   82|      0|    for (const auto& volume : volumes()) {
  ------------------
  |  Branch (82:29): [True: 0, False: 0]
  ------------------
   83|      0|      if (volume.encrypted()) {
  ------------------
  |  Branch (83:11): [True: 0, False: 0]
  ------------------
   84|      0|        _hw_crypto = true;
   85|      0|        break;
   86|      0|      }
   87|      0|    }
   88|      0|  }
   89|      1|}
_ZNK8APFSPool2nxEb:
   91|      1|std::unique_ptr<APFSSuperblock> APFSPool::nx(bool validate) const {
   92|      1|  auto nxsb = std::make_unique<APFSSuperblock>((*this), _nx_block_num);
   93|       |
   94|      1|  if (validate && nxsb->validate_checksum() == false) {
  ------------------
  |  Branch (94:7): [True: 0, False: 1]
  |  Branch (94:19): [True: 0, False: 0]
  ------------------
   95|      0|    throw std::runtime_error("NXSB object checksum failed");
   96|      0|  }
   97|       |
   98|      1|  return nxsb;
   99|      1|}
_ZNK8APFSPool4readEmPcm:
  113|      1|    noexcept {
  114|      1|  return tsk_img_read(_img, address + _offset, buf, buf_size);
  115|      1|}

_ZN14APFSPoolCompatC2IJNSt3__16vectorINS1_4pairIKP12TSK_IMG_INFOKlEENS1_9allocatorIS8_EEEEyEEEDpOT_:
   22|      1|      : TSKPoolCompat<APFSPool>(TSK_POOL_TYPE_APFS, std::forward<Args>(args)...) {
   23|      1|    init_volumes();
   24|      1|  }

_ZN13TSKPoolCompatI8APFSPoolvEC2IJNSt3__16vectorINS3_4pairIKP12TSK_IMG_INFOKlEENS3_9allocatorISA_EEEEyEEE18TSK_POOL_TYPE_ENUMDpOT_:
   38|      1|      : T(std::forward<Args>(args)...) {
   39|       |    ///< \internal the C info structure
   40|      1|    _info.tag = TSK_POOL_INFO_TAG;
  ------------------
  |  |   32|      1|#define TSK_POOL_INFO_TAG 0x504F4C4C
  ------------------
   41|      1|    _info.ctype = type;
   42|      1|    _info.block_size = this->block_size();
   43|      1|    _info.num_blocks = this->num_blocks();
   44|      1|    _info.img_offset = this->first_img_offset();
   45|      1|    _info.num_vols = this->num_vols();
   46|      1|    _info.vol_list = nullptr;
   47|      1|    _info.close = [](const TSK_POOL_INFO *pool) {
   48|      1|      delete static_cast<TSKPoolCompat *>(pool->impl);
   49|      1|    };
   50|      1|    _info.poolstat = [](const TSK_POOL_INFO *pool, FILE *hFile) {
   51|      1|      return static_cast<TSKPoolCompat *>(pool->impl)->poolstat(hFile);
   52|      1|    };
   53|      1|    _info.get_img_info = [](const TSK_POOL_INFO *pool, TSK_DADDR_T pvol_block) {
   54|      1|        return static_cast<TSKPoolCompat *>(pool->impl)->getImageInfo(pool, pvol_block);
   55|      1|    };
   56|      1|    _info.impl = this;
   57|      1|  }

tsk_pool_open_img_sing:
   91|      1|                                            TSK_POOL_TYPE_ENUM type) {
   92|      1|  return tsk_pool_open_img(1, &img, &offset, type);
   93|      1|}
tsk_pool_open_img:
  105|      1|                                       TSK_POOL_TYPE_ENUM type) {
  106|      1|  std::vector<APFSPool::img_t> apfs_v{};
  107|      1|  apfs_v.reserve(num_imgs);
  108|       |
  109|      2|  for (auto i = 0; i < num_imgs; i++) {
  ------------------
  |  Branch (109:20): [True: 1, False: 1]
  ------------------
  110|      1|    apfs_v.emplace_back(imgs[i], offsets[i]);
  111|      1|  }
  112|       |#ifdef HAVE_LIBVSLVM
  113|       |  std::vector<LVMPool::img_t> lvm_v{};
  114|       |
  115|       |  lvm_v.reserve(num_imgs);
  116|       |
  117|       |  for (auto i = 0; i < num_imgs; i++) {
  118|       |    lvm_v.emplace_back(imgs[i], offsets[i]);
  119|       |  }
  120|       |#endif
  121|       |
  122|      1|  const char *error_string = NULL;
  123|       |
  124|      1|  switch (type) {
  ------------------
  |  Branch (124:11): [True: 0, False: 1]
  ------------------
  125|      0|    case TSK_POOL_TYPE_DETECT:
  ------------------
  |  Branch (125:5): [True: 0, False: 1]
  ------------------
  126|      0|      try {
  127|      0|        auto apfs = new APFSPoolCompat(std::move(apfs_v), APFS_POOL_NX_BLOCK_LATEST);
  ------------------
  |  |   18|      0|#define APFS_POOL_NX_BLOCK_LATEST 0xFFFFFFFFFFFFFFFFULL
  ------------------
  128|       |
  129|      0|        return &apfs->pool_info();
  130|      0|      } catch (std::runtime_error &e) {
  131|      0|        error_string = e.what();
  132|      0|      }
  133|       |#ifdef HAVE_LIBVSLVM
  134|       |      try {
  135|       |        auto lvm = new LVMPoolCompat(std::move(lvm_v));
  136|       |
  137|       |        return &lvm->pool_info();
  138|       |      } catch (std::runtime_error &e) {
  139|       |        error_string = e.what();
  140|       |      }
  141|       |#endif
  142|      0|      if (tsk_verbose) {
  ------------------
  |  Branch (142:11): [True: 0, False: 0]
  ------------------
  143|      0|        tsk_fprintf(stderr, "tsk_pool_open_img: pool type detection failed: %s\n",
  144|      0|                    error_string);
  145|      0|      }
  146|      0|      break;
  147|      1|    case TSK_POOL_TYPE_APFS:
  ------------------
  |  Branch (147:5): [True: 1, False: 0]
  ------------------
  148|      1|      try {
  149|      1|        auto apfs = new APFSPoolCompat(std::move(apfs_v), APFS_POOL_NX_BLOCK_LATEST);
  ------------------
  |  |   18|      1|#define APFS_POOL_NX_BLOCK_LATEST 0xFFFFFFFFFFFFFFFFULL
  ------------------
  150|       |
  151|      1|        return &apfs->pool_info();
  152|      1|      } catch (std::runtime_error &e) {
  153|      1|        tsk_error_reset();
  154|      1|        tsk_error_set_errno(TSK_ERR_POOL_UNKTYPE);
  ------------------
  |  |  339|      1|#define TSK_ERR_POOL_UNKTYPE    (TSK_ERR_POOL | 0)
  |  |  ------------------
  |  |  |  |  304|      1|#define TSK_ERR_POOL 0x40000000
  |  |  ------------------
  ------------------
  155|      1|        tsk_error_set_errstr("%s", e.what());
  156|      1|      }
  157|      1|      return nullptr;
  158|       |
  159|       |    // Will fallthrough to TSK_POOL_TYPE_UNSUPP if libvslvm is not available.
  160|      0|    case TSK_POOL_TYPE_LVM:
  ------------------
  |  Branch (160:5): [True: 0, False: 1]
  ------------------
  161|       |#ifdef HAVE_LIBVSLVM
  162|       |      try {
  163|       |        auto lvm = new LVMPoolCompat(std::move(lvm_v));
  164|       |
  165|       |        return &lvm->pool_info();
  166|       |      } catch (std::runtime_error &e) {
  167|       |        tsk_error_reset();
  168|       |        tsk_error_set_errno(TSK_ERR_POOL_UNKTYPE);
  169|       |        tsk_error_set_errstr("%s", e.what());
  170|       |      }
  171|       |      return nullptr;
  172|       |#endif
  173|      0|    case TSK_POOL_TYPE_UNSUPP:
  ------------------
  |  Branch (173:5): [True: 0, False: 1]
  ------------------
  174|       |      // All other pool types are unsupported
  175|      0|      tsk_error_reset();
  176|      0|      tsk_error_set_errno(TSK_ERR_POOL_UNSUPTYPE);
  ------------------
  |  |  340|      0|#define TSK_ERR_POOL_UNSUPTYPE  (TSK_ERR_IMG | 1)
  |  |  ------------------
  |  |  |  |  299|      0|#define TSK_ERR_IMG	0x02000000
  |  |  ------------------
  ------------------
  177|      0|      tsk_error_set_errstr("%d", type);
  178|      0|      return nullptr;
  179|      1|  }
  180|       |
  181|       |  // All other pool types are unsupported
  182|      0|  tsk_error_reset();
  183|      0|  tsk_error_set_errno(TSK_ERR_POOL_UNSUPTYPE);
  ------------------
  |  |  340|      0|#define TSK_ERR_POOL_UNSUPTYPE  (TSK_ERR_IMG | 1)
  |  |  ------------------
  |  |  |  |  299|      0|#define TSK_ERR_IMG	0x02000000
  |  |  ------------------
  ------------------
  184|      0|  tsk_error_set_errstr("%d", type);
  185|      0|  return nullptr;
  186|      1|}

_ZN7TSKPoolD2Ev:
   39|      1|  virtual ~TSKPool() = default;
_ZN7TSKPoolC2EONSt3__16vectorINS0_4pairIKP12TSK_IMG_INFOKlEENS0_9allocatorIS7_EEEE:
   67|      1|  TSKPool(std::vector<img_t> &&imgs) noexcept : _members{std::move(imgs)} {}

LLVMFuzzerTestOneInput:
   23|      1|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
   24|      1|  TSK_IMG_INFO* img;
   25|      1|  TSK_IMG_INFO* pool_img;
   26|      1|  TSK_FS_INFO* fs;
   27|      1|  const TSK_POOL_INFO* pool;
   28|       |
   29|      1|  img = mem_open(data, size);
   30|      1|  if (img == nullptr) {
  ------------------
  |  Branch (30:7): [True: 0, False: 1]
  ------------------
   31|      0|    return 0;
   32|      0|  }
   33|      1|  pool = tsk_pool_open_img_sing(img, 0, TSK_POOL_TYPE_APFS);
   34|       |
   35|      1|  if (pool == nullptr) {
  ------------------
  |  Branch (35:7): [True: 1, False: 0]
  ------------------
   36|      1|    goto out_img;
   37|      1|  }
   38|       |  // Pool start block is APFS container specific and is hard coded for now
   39|      0|  pool_img = pool->get_img_info(pool, (TSK_DADDR_T) 106);
   40|       |
   41|      0|  if (pool_img == nullptr) {
  ------------------
  |  Branch (41:7): [True: 0, False: 0]
  ------------------
   42|      0|    goto out_pool;
   43|      0|  }
   44|      0|  fs = tsk_fs_open_img_decrypt(pool_img, 0, TSK_FS_TYPE_APFS_DETECT, "");
   45|       |
   46|      0|  if (fs != nullptr) {
  ------------------
  |  Branch (46:7): [True: 0, False: 0]
  ------------------
   47|      0|    tsk_fs_fls(fs, TSK_FS_FLS_FULL, fs->root_inum, TSK_FS_DIR_WALK_FLAG_RECURSE, nullptr, 0);
   48|       |
   49|      0|    fs->close(fs);
   50|      0|  }
   51|      0|  tsk_img_close(pool_img);
   52|       |
   53|      0|out_pool:
   54|      0|  tsk_pool_close(pool);
   55|       |
   56|      1|out_img:
   57|      1|  tsk_img_close(img);
   58|       |
   59|      1|  return 0;
   60|      0|}

