Skip to content

MemCompare

Description

Compare memory regions. A zero byte count returns 0 without reading either pointer.

Parameters

Name Direction Description
p1 in First memory region.
p2 in Second memory region.
n in Number of bytes to compare.

Success

Returns 0 if equal, <0 if p1<p2, >0 if p1>p2.

Failure

Aborts via LOG_FATAL when n > 0 and either p1 or p2 is NULL.

Usage example (Cross-references)

Usage examples (Cross-references)
    
    __attribute__((used)) int memcmp(const void *a, const void *b, freestanding_size_t n) {
        return (int)MemCompare(a, b, (size)n);
    }
    #include <Misra/Std/Memory.h>
    
    i32 MemCompare(const void *p1, const void *p2, size n) {
        if (n == 0) {
            return 0;
                continue;
            }
            if (MemCompare(haystack + pos, needle, needle_len) == 0) {
                return haystack + pos;
            }
    
        min = StrLen(a) < StrLen(b) ? StrLen(a) : StrLen(b);
        cmp = MemCompare(StrBegin(a), StrBegin(b), min);
    
        if (cmp != 0) {
    
    static inline bool starts_with(Zstr data, size data_len, Zstr prefix, size prefix_len) {
        return data_len >= prefix_len && MemCompare(data, prefix, prefix_len) == 0;
    }
    
    static inline bool ends_with(Zstr data, size data_len, Zstr suffix, size suffix_len) {
        return data_len >= suffix_len && MemCompare(data + data_len - suffix_len, suffix, suffix_len) == 0;
    }
    
        while (i + match_len <= s->length && replaced < count) {
            if (MemCompare(s->data + i, match, match_len) == 0) {
                StrDeleteRange(s, i, match_len);
                StrInsertMany(s, replacement, replacement_len, i);
        if (main->build_id_size != sidecar->build_id_size)
            return false;
        return MemCompare(main->build_id, sidecar->build_id, main->build_id_size) == 0;
    }
        const PeCodeViewInfo *pe_cv   = PeCodeView(&entry->pe);
        const PdbInfo        *pdb_inf = PdbInfoStream(&entry->pdb);
        if (pe_cv->age != pdb_inf->age || MemCompare(pe_cv->guid, pdb_inf->guid, 16) != 0) {
            LOG_ERROR("PdbCache: GUID/age mismatch between PE and PDB for {}", entry->module_path);
            PdbDeinit(&entry->pdb);
            char sep;
            if (StrIterRemainingLength(&si) > kw_len &&
                MemCompare(StrIterDataAt(&si, StrIterIndex(&si)), NS_KEYWORD, kw_len) == 0 &&
                StrIterPeekAt(&si, (i64)kw_len, &sep) && (sep == ' ' || sep == '\t')) {
                StrIterMustMove(&si, (i64)kw_len);
        StrDeinit(&path);
    
        if (!MachoHasUuid(&e->dsym) || MemCompare(MachoUuid(&e->dsym), MachoUuid(&e->main), 16) != 0) {
            LOG_ERROR("MachoCache: dSYM UUID mismatch for {}", e->module_path);
            MachoDeinit(&e->dsym);
            return false;
        }
        if (MemCompare(BufData(&self->data), MSF_MAGIC_7, sizeof(MSF_MAGIC_7)) != 0) {
            LOG_ERROR("PDB: bad MSF magic (not 7.00)");
            return false;
        // rejected. A constant flags value drops O_RDONLY and/or adds O_TRUNC,
        // breaking at least one of these.
        ok = ok && (got == 7) && (MemCompare(buf, "read-me", 7) == 0);
        ok = ok && (FileWrite(&f, "X", 1) == -1);
        FileClose(&f);
        // Exact 5-byte read of the leading content.
        i64 got = FileRead(&f, buf, 5);
        ok      = ok && (got == 5) && (MemCompare(buf, "ABCDE", 5) == 0);
        FileClose(&f);
        // And reading now succeeds again from the top.
        char buf2[3] = {0};
        ok           = ok && (FileRead(&f, buf2, 3) == 3) && (MemCompare(buf2, "abc", 3) == 0);
        FileClose(&f);
        FileClose(&r);
    
        ok = ok && (got == (i64)N) && (BufLength(&dst) == (size)N) && (MemCompare(BufData(&dst), BufData(&src), N) == 0);
    
        BufDeinit(&src);
        ok           = ok && (FileSeek(&f, 0, FILE_SEEK_SET) == 0);
        char buf[10] = {0};
        ok           = ok && (FileRead(&f, buf, 9) == 9) && (MemCompare(buf, "temp-data", 9) == 0);
        FileClose(&f);
            0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // u64 BE
        };
        bool ok = BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        BufDeinit(&b);
        DefaultAllocatorDeinit(&alloc);
        BufWriteULeb128(&b, 16384);
        const u8 expect_uleb[] = {0x00, 0x7F, 0x80, 0x01, 0x80, 0x80, 0x01};
        if (BufLength(&b) != sizeof(expect_uleb) || MemCompare(BufData(&b), expect_uleb, sizeof(expect_uleb)) != 0) {
            BufDeinit(&b);
            DefaultAllocatorDeinit(&alloc);
        BufWriteSLeb128(&b, -64);
        const u8 expect_sleb[] = {0x00, 0x7F, 0xC0, 0x00, 0x40};
        bool ok = BufLength(&b) == sizeof(expect_sleb) && MemCompare(BufData(&b), expect_sleb, sizeof(expect_sleb)) == 0;
    
        BufDeinit(&b);
        BufWriteZstr(&b, "hi");
        const u8 expect[] = {'h', 'i', 0};
        bool     ok       = BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        BufDeinit(&b);
        DefaultAllocatorDeinit(&alloc);
        bool     ok       = BufAppendFmt(&b, "{<2r}{>4r}", (u16)0xCAFE, (u32)0xDEADBEEF);
        const u8 expect[] = {0x99, 0xFE, 0xCA, 0xDE, 0xAD, 0xBE, 0xEF};
        ok                = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        BufDeinit(&b);
        DefaultAllocatorDeinit(&alloc);
        bool     ok       = BufWriteFmt(&b, "{<2r}", (u16)0x1234);
        const u8 expect[] = {0x34, 0x12};
        ok                = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        BufDeinit(&b);
        DefaultAllocatorDeinit(&alloc);
            0x11
        };
        ok = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
    
        // Out-of-range patch must fail and leave the buf unchanged.
        ok = ok && !BufPatchFmt(&b, BufLength(&b), "{<2r}", (u16)0);
        ok = ok && BufLength(&b) == BufLength(&snapshot);
        ok = ok && MemCompare(BufData(&b), BufData(&snapshot), BufLength(&b)) == 0;
        BufDeinit(&snapshot);
    
        bool result = written == 4;
        result      = result && (MemCompare(out, bytes, sizeof(bytes)) == 0);
        result      = result && (ZstrCompare(StrBegin(&text), "cdef1234") == 0);
    
        bool result = written == 4;
        result      = result && (MemCompare(out, bytes, sizeof(bytes)) == 0);
        result      = result && (ZstrCompare(StrBegin(&text), "12345678") == 0);
    
        bool result = (written == 2);
        result      = result && (MemCompare(out, expect, 2) == 0);
    
        IntDeinit(&value);
    
        bool result = (written == 2);
        result      = result && (MemCompare(out, expect, 2) == 0);
    
        IntDeinit(&value);
        bool             ok       = BufAppendFmt(&b, "{<1r}", (u8)0x7E);
        const u8         expect[] = {0x7E};
        ok = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        BufDeinit(&b);
        DefaultAllocatorDeinit(&alloc);
        bool             ok       = BufAppendFmt(&b, "{<8r}", (i64)0x0102030405060708ll);
        const u8         expect[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
        ok = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        BufDeinit(&b);
        DefaultAllocatorDeinit(&alloc);
        bool     ok       = BufAppendFmt(&b, "{<8r}", in.f);
        const u8 expect[] = {0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
        ok                = ok && BufLength(&b) == sizeof(expect) && MemCompare(BufData(&b), expect, sizeof(expect)) == 0;
        BufDeinit(&b);
        DefaultAllocatorDeinit(&alloc);
        char buf[64];
        i64  got = SocketRecv(&server, buf, sizeof(buf));
        bool ok  = got == (i64)n && MemCompare(buf, payload, n) == 0;
    
        SocketClose(&server);
        char buf1[64];
        i64  g1 = SocketRecv(&server, buf1, sizeof(buf1));
        ok      = ok && g1 == (i64)n1 && MemCompare(buf1, c2s, n1) == 0;
    
        // server -> client (different payload + length so a swapped fd or a
        char buf2[64];
        i64  g2 = SocketRecv(&client, buf2, sizeof(buf2));
        ok      = ok && g2 == (i64)n2 && MemCompare(buf2, s2c, n2) == 0;
    
        SocketClose(&server);
        char buf[32];
        i64  got = SocketRecv(&server, buf, sizeof(buf));
        ok       = ok && got == (i64)n && MemCompare(buf, payload, n) == 0;
    
        SocketClose(&server);
        char buf[32];
        i64  got = SocketRecv(&server, buf, sizeof(buf));
        ok       = ok && got == (i64)n && MemCompare(buf, payload, n) == 0;
    
        SocketClose(&server);
        char buf[16];
        i64  got = SocketRecv(&server, buf, sizeof(buf));
        ok       = ok && got == (i64)n && MemCompare(buf, payload, n) == 0;
    
        SocketClose(&server);
        ok = ok && pe.codeview.present;
        ok = ok && pe.codeview.age == 0x2a;
        ok = ok && MemCompare(pe.codeview.guid, kGuid, 16) == 0;
        ok = ok && pe.codeview.pdb_path && ZstrCompare(pe.codeview.pdb_path, kPdbPath) == 0;
        }
        bool ok = pe.codeview.present == true; // L494 present=true
        ok      = ok && MemCompare(pe.codeview.guid, kGuid, 16) == 0;
        ok      = ok && pe.codeview.age == CV_AGE;
        ok      = ok && pe.codeview.pdb_path && ZstrCompare(pe.codeview.pdb_path, kPdbPath) == 0;
            return false;
        }
        bool ok = pe.codeview.present == true && pe.codeview.age == CV_AGE && MemCompare(pe.codeview.guid, kGuid, 16) == 0;
        PeDeinit(&pe);
        DefaultAllocatorDeinit(&alloc);
            return false;
        }
        bool ok = pe.codeview.present == true && pe.codeview.age == CV_AGE && MemCompare(pe.codeview.guid, kGuid, 16) == 0;
        PeDeinit(&pe);
        DefaultAllocatorDeinit(&alloc);
            return false;
        }
        bool ok = pe.codeview.present == true && pe.codeview.age == CV_AGE && MemCompare(pe.codeview.guid, kGuid, 16) == 0;
        PeDeinit(&pe);
        DefaultAllocatorDeinit(&alloc);
            return false;
        }
        bool ok = pe.codeview.present == true && pe.codeview.age == CV_AGE && MemCompare(pe.codeview.guid, kGuid, 16) == 0;
        PeDeinit(&pe);
        DefaultAllocatorDeinit(&alloc);
        ok = ok && pdb.info.signature == 0xdeadbeef;
        ok = ok && pdb.info.age == 0x42;
        ok = ok && MemCompare(pdb.info.guid, kGuid, 16) == 0;
    
        PdbDeinit(&pdb);
        ok                = ok && pi->signature == 0x05060708;
        ok                = ok && pi->age == 0x090A0B0C;
        ok                = ok && MemCompare(pi->guid, kGuid, 16) == 0;
    
        PdbDeinit(&pdb);
        }
        ok = pdb.num_streams == 2 && pdb.info.version == 20040203 && pdb.info.age == 0x42 &&
             MemCompare(pdb.info.guid, kGuid, 16) == 0;
    
        PdbDeinit(&pdb);
    
        ok = m.cputype == 0x01000007u && m.filetype == MACHO_FILE_TYPE_EXECUTE;
        ok = ok && m.has_uuid && MemCompare(m.uuid, kUuid, 16) == 0;
        ok = ok && VecLen(&m.segments) == 1;
        ok = ok && ZstrCompare(VecPtrAt(&m.segments, 0)->name, "__TEXT") == 0;
        Macho m;
        bool  ok = open_blob(&m, b, BUF, &alloc);
        ok       = ok && m.has_uuid && MemCompare(m.uuid, kUuid, 16) == 0;
        if (ok)
            MachoDeinit(&m);
        // Canonical-true check: real code stores exactly `true` (== 1); the
        // mutant stores 42, so `== true` is false under the mutation.
        ok = ok && m.has_uuid == true && MemCompare(m.uuid, kUuid, 16) == 0;
        if (ok)
            MachoDeinit(&m);
    
        bool ok = elf.build_id != NULL && elf.build_id_size == BUILD_ID_LEN &&
                  MemCompare(elf.build_id, kBuildId, BUILD_ID_LEN) == 0;
    
        ok = ok && elf.debuglink_name != NULL && ZstrCompare(elf.debuglink_name, "foo.debug") == 0 &&
        }
        bool ok =
            elf.build_id != NULL && elf.build_id_size == sizeof(desc) && MemCompare(elf.build_id, desc, sizeof(desc)) == 0;
        ElfDeinit(&elf);
        DefaultAllocatorDeinit(&alloc);
        }
        bool ok = elf.build_id != NULL && elf.build_id_size == BUILD_ID_LEN &&
                  MemCompare(elf.build_id, kBuildId, BUILD_ID_LEN) == 0;
        ok = ok && elf.debuglink_name != NULL && ZstrCompare(elf.debuglink_name, "foo.debug") == 0 &&
             elf.debuglink_crc == DEBUGLINK_CRC;
        Zstr msg_want  = "Hello, \"World\"!";
        Zstr data_want = "line1\nline2\ttab";
        if (StrLen(&obj.path) != ZstrLen(path_want) || MemCompare(StrBegin(&obj.path), path_want, StrLen(&obj.path)) != 0) {
            WriteFmtLn("[DEBUG] Special characters FAILED: path content wrong");
            success = false;
        }
        if (StrLen(&obj.message) != ZstrLen(msg_want) ||
            MemCompare(StrBegin(&obj.message), msg_want, StrLen(&obj.message)) != 0) {
            WriteFmtLn("[DEBUG] Special characters FAILED: message content wrong");
            success = false;
            success = false;
        }
        if (StrLen(&obj.data) != ZstrLen(data_want) || MemCompare(StrBegin(&obj.data), data_want, StrLen(&obj.data)) != 0) {
            WriteFmtLn("[DEBUG] Special characters FAILED: data content wrong");
            success = false;
                success = false;
            }
            if (StrLen(&out) != 5 || MemCompare(StrBegin(&out), "plain", 5) != 0) {
                WriteFmtLn("[DEBUG] JReadString decoded plain string wrong: len={}", StrLen(&out));
                success = false;
Last updated on