Skip to content

IterIndex

Description

Absolute cursor index within the iterator’s backing region. Read-only accessor for (mi)->pos; use it from outside the Iter namespace instead of reaching for the field. Forward iterators report a value in [0, length] (where length is the past-end position); reverse iterators report [0, length-1] plus the (size)-1 past-start sentinel.

Usage example (Cross-references)

Usage examples (Cross-references)
        // plus the 16-byte segname plus the body.
        IterMustMove(cmd, 8); // skip cmd(4) + cmdsize(4) prefix
        MemCopy(seg.name, IterDataAt(cmd, IterIndex(cmd)), 16);
        seg.name[16] = '\0';
        IterMustMove(cmd, 16);
        // SECT64_SIZE bytes.
        for (u32 i = 0; i < seg.nsects; ++i) {
            if (IterIndex(cmd) + SECT64_SIZE > IterLength(cmd)) {
                LOG_ERROR("MachO: section table overruns LC_SEGMENT_64");
                return false;
            MachoSection sec;
            MemSet(&sec, 0, sizeof(sec));
            MemCopy(sec.section, IterDataAt(&sec_it, IterIndex(&sec_it)), 16);
            sec.section[16] = '\0';
            IterMustMove(&sec_it, 16);
            sec.section[16] = '\0';
            IterMustMove(&sec_it, 16);
            MemCopy(sec.segment, IterDataAt(&sec_it, IterIndex(&sec_it)), 16);
            sec.segment[16] = '\0';
            IterMustMove(&sec_it, 16);
        // proves the 8-byte prefix plus the 16-byte UUID payload fit.
        IterMustMove(cmd, 8); // skip cmd + cmdsize prefix
        MemCopy(ctx->out->uuid, IterDataAt(cmd, IterIndex(cmd)), 16);
        ctx->out->has_uuid = true;
        return true;
        if (IterRemainingLength(cur) < out->std_opcode_lengths_count)
            return false;
        out->standard_opcode_lengths = IterDataAt(cur, IterIndex(cur));
        // Must-precondition: the `IterRemainingLength < count` guard above
        // proves the cursor has at least `count` bytes left in the buffer.
        // proves the cursor has at least `count` bytes left in the buffer.
        IterMustMove(cur, (i64)out->std_opcode_lengths_count);
        out->strings_start = IterDataAt(cur, IterIndex(cur));
        return true;
    }
    // start of the line number program body.
    static bool skip_line_program_tables(BufIter *cur) {
        while (IterIndex(cur) < IterLength(cur) && *IterDataAt(cur, IterIndex(cur)) != 0) {
            if (!BufReadZstr(cur))
                return false;
        // Must-precondition: the surrounding `IterIndex < IterLength` test
        // proves there is at least one more byte to consume (the NUL).
        if (IterIndex(cur) < IterLength(cur))
            IterMustNext(cur); // empty terminator
            IterMustNext(cur); // empty terminator
    
        while (IterIndex(cur) < IterLength(cur) && *IterDataAt(cur, IterIndex(cur)) != 0) {
            if (!BufReadZstr(cur))
                return false;
        // Must-precondition: same `IterIndex < IterLength` proof as the
        // include_directories terminator above.
        if (IterIndex(cur) < IterLength(cur))
            IterMustNext(cur); // empty terminator
        return true;
    static bool collect_cu_strings(BufIter cur, Str *pool, CuStrings *cs) {
        // include_directories
        while (IterIndex(&cur) < IterLength(&cur) && *IterDataAt(&cur, IterIndex(&cur)) != 0) {
            Zstr dir = BufReadZstr(&cur);
            if (!dir)
        // Must-precondition: `IterIndex < IterLength` proves there is a
        // terminator byte left to consume.
        if (IterIndex(&cur) < IterLength(&cur))
            IterMustNext(&cur); // empty terminator
    
        // file_names
        while (IterIndex(&cur) < IterLength(&cur) && *IterDataAt(&cur, IterIndex(&cur)) != 0) {
            Zstr name = BufReadZstr(&cur);
            if (!name)
        lnp_reset(&st, hdr->default_is_stmt);
    
        while (IterDataAt(&cur, IterIndex(&cur)) < prog_end) {
            u8 op = 0;
            if (!BufReadU8(&cur, &op))
                if (!BufReadULeb128(&cur, &length))
                    return false;
                if (length == 0 || (u64)(prog_end - IterDataAt(&cur, IterIndex(&cur))) < length)
                    return false;
                const u8 *body_end = IterDataAt(&cur, IterIndex(&cur)) + length;
                if (length == 0 || (u64)(prog_end - IterDataAt(&cur, IterIndex(&cur))) < length)
                    return false;
                const u8 *body_end = IterDataAt(&cur, IterIndex(&cur)) + length;
                u8        sub_op   = 0;
                if (!BufReadU8(&cur, &sub_op))
                    case DW_LNE_SET_ADDRESS :
                        // operand size = remaining body bytes; on x86-64 always 8.
                        if (body_end - IterDataAt(&cur, IterIndex(&cur)) == 8) {
                            if (!BufReadU64LE(&cur, &st.address))
                                return false;
                            if (!BufReadU64LE(&cur, &st.address))
                                return false;
                        } else if (body_end - IterDataAt(&cur, IterIndex(&cur)) == 4) {
                            u32 a32 = 0;
                            if (!BufReadU32LE(&cur, &a32))
                // above proved `length <= prog_end - here`, and switch arms
                // only consume bytes within the body. Jump to body_end.
                IterMustMove(&cur, (i64)((size)(body_end - IterDataAt(&cur, 0)) - IterIndex(&cur)));
            } else if (op < hdr->opcode_base) {
                // Standard opcode
        bool ok = true;
        while (IterRemainingLength(&section_cur) > 0) {
            const u8 *unit_start  = IterDataAt(&section_cur, IterIndex(&section_cur));
            u32       unit_length = 0;
            BufIter   peek        = section_cur;
            }
            const u8 *unit_end     = unit_start + 4 + unit_length;
            size      unit_end_pos = IterIndex(&section_cur) + 4 + unit_length;
    
            // Decode header (fields only), then walk the directory / file
                // consumed gives us the size of this whole unit.
                // unit_end_pos was bounded above against the section end.
                IterMustMove(&section_cur, (i64)(unit_end_pos - IterIndex(&section_cur)));
                continue;
            }
            cu_strings_deinit(&cs);
            // Same bounds proof as the unsupported-version branch above.
            IterMustMove(&section_cur, (i64)(unit_end_pos - IterIndex(&section_cur)));
        }
        bool ok = true;
        while (IterRemainingLength(&info_cur) > 0) {
            size unit_start_pos = IterIndex(&info_cur);
    
            u32 unit_length;
                // up the rest of the binary's CUs in case some are v4.
                // unit_end_pos was bounded above against IterLength(&info_cur).
                IterMustMove(&info_cur, (i64)(unit_end_pos - IterIndex(&info_cur)));
                continue;
            }
            // info_cur position up to unit_end_pos).
            BufIter die_cur =
                BufIterFromMemory(IterDataAt(&info_cur, IterIndex(&info_cur)), unit_end_pos - IterIndex(&info_cur));
            if (!walk_cu_dies(die_cur, &abbrevs, addr_size, str_bytes, str_size, &out->string_pool, &pending)) {
                abbrev_table_deinit(&abbrevs);
    
            // Same bounds proof: unit_end_pos was bounded above.
            IterMustMove(&info_cur, (i64)(unit_end_pos - IterIndex(&info_cur)));
        }
                    continue;
                }
                Zstr name = (Zstr)IterDataAt(&body, IterIndex(&body));
    
                (void)flags; // permissive: we don't filter by FUNCTION bit;
            if (aug_len > IterRemainingLength(body))
                return false;
            size aug_end_pos = IterIndex(body) + aug_len;
    
            StrIter aug_it = StrIterFromZstr(augmentation + 1);
            // before we started reading; even a partial-arm read leaves the
            // cursor inside `[aug_start, aug_end_pos]`.
            IterMustMove(body, (i64)(aug_end_pos - IterIndex(body)));
        }
        }
    
        out->initial_instructions      = IterDataAt(body, IterIndex(body));
        out->initial_instructions_size = IterRemainingLength(body);
        return true;
        u64 pc_begin = 0;
        {
            u64 here = eh_byte_vaddr(section_data, section_addr, IterDataAt(body, IterIndex(body)));
            if (!decode_eh_ptr(body, cie->fde_pointer_encoding, here, &pc_begin))
                return false;
        u64 pc_range  = 0;
        {
            u64 here = eh_byte_vaddr(section_data, section_addr, IterDataAt(body, IterIndex(body)));
            if (!decode_eh_ptr(body, range_enc, here, &pc_range))
                return false;
        }
    
        out->instructions      = IterDataAt(body, IterIndex(body));
        out->instructions_size = IterRemainingLength(body);
        return true;
        BufIter section_cur = BufIterFromMemory(section_data, eh->size);
        while (IterRemainingLength(&section_cur) > 0) {
            const u8 *rec_start = IterDataAt(&section_cur, IterIndex(&section_cur));
            u32       length32  = 0;
            if (!BufReadU32LE(&section_cur, &length32))
            // We've already consumed 4 bytes for `id`, so the body iter
            // covers (id field's start) + length32 bytes.
            size body_pos_start = IterIndex(&section_cur) - 4;
    
            // In .eh_frame, id==0 means CIE; nonzero is the CIE_pointer for FDE
                // Body iter starts just after the id field (since parse_cie
                // doesn't re-read id) and spans the remainder of the record.
                BufIter body = BufIterFromMemory(IterDataAt(&section_cur, IterIndex(&section_cur)), length32 - 4);
                if (parse_cie(&body, cie_offset, &cie)) {
                    if (!VecPushBackR(&out->cies, cie)) {
                // miss every CIE (best case) or alias one (worst case).
                // Skip the FDE explicitly.
                u64 id_field_off = (u64)(IterIndex(&section_cur) - 4);
                if ((u64)id > id_field_off) {
                    // length32 bounds were validated against IterRemainingLength
                u64      cie_offset = id_field_off - (u64)id;
                DwarfFde fde;
                BufIter  body = BufIterFromMemory(IterDataAt(&section_cur, IterIndex(&section_cur)), length32 - 4);
                if (parse_fde(&body, rec_start, cie_offset, out, section_data, eh->addr, &fde)) {
                    if (!VecPushBackR(&out->fdes, fde)) {
    
            // Same bounds proof as above: jump past this record's body.
            IterMustMove(&section_cur, (i64)((body_pos_start + length32) - IterIndex(&section_cur)));
        }
        u32       hops      = 0;
        bool      jumped    = false;
        u64       linear_p  = IterIndex(it);
        u64       cur       = IterIndex(it);
        u64       name_len  = 0;
        bool      jumped    = false;
        u64       linear_p  = IterIndex(it);
        u64       cur       = IterIndex(it);
        u64       name_len  = 0;
        u64       label_idx = 0;
                // compression-pointer branch sets `linear_p = cur + 2` BEFORE
                // jumping). Net delta is always >= 0 and within `IterLength(it)`.
                IterMustMove(it, (i64)(linear_p - IterIndex(it)));
                return true;
            }
        rec->ttl    = ttl;
    
        if (IterIndex(it) + (u64)rdlength > IterLength(it)) {
            return false;
        }
            return false;
        }
        u64 rdata_start = IterIndex(it);
    
        // Stash raw rdata.
        ctx->num_sections = num_sec;
        ctx->opt_hdr_size = size_opt;
        *out_opt_offset   = (u64)(IterDataAt(&c, IterIndex(&c)) - BufData(&ctx->out->data));
        return true;
    }
            // 8-byte name: bytes, not a numeric, so copy + advance manually.
            // IterRemainingLength >= 40 bound above proves 8 bytes are live.
            MemCopy(s.name, IterDataAt(&c, IterIndex(&c)), 8);
            s.name[8] = '\0';
            IterMustMove(&c, 8);
                continue;
            // Same proof: 16 bytes are live.
            MemCopy(cv->guid, IterDataAt(&cv_cur, IterIndex(&cv_cur)), 16);
            IterMustMove(&cv_cur, 16);
            if (!BufReadU32LE(&cv_cur, &cv->age))
                continue;
            // Verify the trailing path is NUL-terminated inside the record.
            const u8 *path_start = IterDataAt(&cv_cur, IterIndex(&cv_cur));
            const u8 *region_end = IterDataAt(&cv_cur, IterLength(&cv_cur));
            bool      terminated = false;
        u8       v      = 0;
        IterRead(&it, &v);
        size pos_before = IterIndex(&it);
        u8   sentinel   = 0xAA;
        v               = sentinel;
        }
        // Failed read must leave both `pos` and `*out` untouched.
        return IterIndex(&it) == pos_before && v == sentinel;
    }
        }
        // Peeks must not advance the cursor.
        return IterIndex(&it) == 2;
    }
        const u8 buf[5] = {0};
        BufIter  it     = BufIterFromMemory(buf, 5);
        if (!IterMove(&it, 3) || IterIndex(&it) != 3) {
            return false;
        }
            return false;
        }
        if (!IterMove(&it, -2) || IterIndex(&it) != 1) {
            return false;
        }
        const u8 buf[3] = {0};
        BufIter  it     = BufIterFromMemory(buf, 3);
        if (!IterMove(&it, 3) || IterIndex(&it) != 3) {
            return false;
        }
        const u8 buf[3] = {0};
        BufIter  it     = BufIterFromMemory(buf, 3);
        size     before = IterIndex(&it);
        if (IterMove(&it, 4)) {
            return false;
            return false;
        }
        return IterIndex(&it) == before;
    }
            return false;
        }
        return IterIndex(&it) == 0;
    }
        BufIter  it     = from_rev(buf, 5);
        // start at pos=4
        if (!IterMove(&it, 2) || IterIndex(&it) != 2) {
            return false;
        }
        }
        // step backward in reverse direction (n=-1, effective +1)
        if (!IterMove(&it, -1) || IterIndex(&it) != 3) {
            return false;
        }
        BufIter  it     = from_rev(buf, 3);
        // pos=2, dir=-1, move by 3 lands on sentinel pos=-1
        if (!IterMove(&it, 3) || IterIndex(&it) != (size)-1) {
            return false;
        }
        BufIter  it     = from_rev(buf, 3);
        // pos=2, dir=-1, move by 4 would land at pos=-2 — invalid
        size before = IterIndex(&it);
        if (IterMove(&it, 4)) {
            return false;
            return false;
        }
        return IterIndex(&it) == before;
    }
        const u8 buf[3] = {0};
        BufIter  it     = BufIterFromMemory(buf, 3);
        if (!IterNext(&it) || IterIndex(&it) != 1) {
            return false;
        }
            return false;
        }
        if (!IterNext(&it) || IterIndex(&it) != 2) {
            return false;
        }
            return false;
        }
        if (!IterPrev(&it) || IterIndex(&it) != 1) {
            return false;
        }
            return false;
        }
        if (!IterPrev(&it) || IterIndex(&it) != 0) {
            return false;
        }
    /// TAGS: StrIter, Position, Alias
    ///
    #define StrIterIndex(mi) IterIndex(mi)
    
    ///
Last updated on