WerWolv / ImHex-Patterns

Hex patterns, include patterns and magic files for the use with the ImHex Hex Editor
https://github.com/WerWolv/ImHex
GNU General Public License v2.0
656 stars 172 forks source link

Inconsistent results from std::hash::crc32() #312

Open phipolis opened 1 week ago

phipolis commented 1 week ago

I'm observing unexpected behavior in ImHex 1.35.4 where std::hash::crc32() returns a different result on every evaluation in the pattern editor console.

Context: I am writing a pattern to parse a 512-byte structure. The first 8 bytes describe a checksum and seed checking the 504 bytes that follow. (It's a CRC32-C variant - no xorout) I can produce the expected result by selecting the 504 bytes in the 'Hashes' view (screenshot). However I'm unable to achieve the same result in the pattern editor. Instead I am seeing constantly shifting values.

image

The sketch below illustrates what I'm seeing. Am I misusing something or does it seem like an issue with std::hash::crc32()?

import std.hash;
import type.magic;
#define FVAULT2_VOL_HEADER_SIZE 512
#define CRC32C_POLYNOMIAL 0x1edc6f41

struct CRC32_CHECKSUM { 
    u32 value;
    u32 seed;
};

struct VOLUME_HEADER {
  CRC32_CHECKSUM crc32;
  std::print("CRC expected: {0:#x} / seed {1:#x}", crc32.value, crc32.seed);

  // ... [FIELDS OMITTED] ...

  // Jump back & capture all field bytes as a whole:
  $ = addressof(this) + sizeof(crc32);
  std::print("CRC32C: {} bytes @{}", FVAULT2_VOL_HEADER_SIZE - sizeof(crc32), $);
  u8 crcBytes[FVAULT2_VOL_HEADER_SIZE - sizeof(crc32)] [[hidden]];
  u32 crc_computed_1 = std::hash::crc32(crcBytes, crc32.seed, CRC32C_POLYNOMIAL, 0x0, true, true);
  std::print("Calculated1 {0:#x}", crc_computed_1);

  // Try again with explicit addresses 
  $ = 0x8;
  u8 crcBytes_2[504];
  u32 crc_computed_2 = std::hash::crc32(crcBytes_2, crc32.seed, CRC32C_POLYNOMIAL, 0x0, true, true);
  std::print("Calculated2 {0:#x}", crc_computed_2);
};
VOLUME_HEADER volume_header @ 0x00;

Evaluation:

I: CRC expected: 0x4d65756 / seed 0xffffffff
I: CRC32C: 504 bytes @8
I: Calculated1 0xea9dc936
I: Calculated2 0x4b652509
I: Pattern exited with code: 0
I: Evaluation took 0.0195119s

Next evaluation:

I: CRC expected: 0x4d65756 / seed 0xffffffff
I: CRC32C: 504 bytes @8
I: Calculated1 0xca7d6643
I: Calculated2 0x3be812d3
I: Pattern exited with code: 0
I: Evaluation took 0.0222181s
paxcut commented 1 week ago

I tested using the standard crc32 and I also get results that change on every run and that obviously differ from any other crc32 implementation I tried. The only way I can get it to behave consistently and give the expected result is to use an array of chars instead of using u8 or s8.

I couldn't test your code because no input file is provided, but you can try and see if this is related to what you are seeing. To test this in your code, instead of using

u8 crcBytes[FVAULT2_VOL_HEADER_SIZE - sizeof(crc32)] [[hidden]];

try using

char crcBytes[FVAULT2_VOL_HEADER_SIZE - sizeof(crc32)] [[hidden]];

and the same for the other tests. Why does it need to use chars? I am not sure. Somebody who knows more about crc32 may know why this is happening. There is also the possibility of this being a bug but I can't imagine what the bug would be or how to fix it.

phipolis commented 6 days ago

@paxcut As you say, it works as expected with type char instead of u8. Thank you for the suggestion!

Here is a 512B sample file with a CRC at the beginning that satisfies the pattern: ImHex-Patterns_Issue_312_Sample.zip