fix: CRC im Settings-Record dort schreiben, wo der Leser sie erwartet
nl_settings_save() rechnete die CRC über [0, offsetof(rec_t, crc)) und legte sie dort ab, read_rec() liest sie bei sizeof(rec_hdr_t) + hdr.length. Beide Offsets stimmen nur überein, solange sizeof(nl_settings_t) ein Vielfaches von 4 ist (aktuell 204). Ein zusätzliches uint16_t - in Plan 4 (Migration) sehr wahrscheinlich - macht 206, und jeder gespeicherte Record fiele beim nächsten Boot still durch die CRC: WLAN, Token und Name wären auf allen Lampen weg. Geschrieben wird jetzt explizit bei NL_SETTINGS_CRC_OFF(length), also exakt an der Leseposition; dazu eine Übersetzungszeit-Zusicherung, dass die Nutzdaten direkt hinter dem Header beginnen (die CRC läuft auf beiden Seiten über einen zusammenhängenden Block). Test: test_crc_offset_matches_reader prüft die Symmetrie unabhängig von der Strukturgröße. Gegenprobe mit einem zusätzlichen uint16_t im Struct: mit der alten Schreibposition fallen vier Settings-Tests, mit der neuen keiner.
This commit is contained in:
@@ -135,6 +135,30 @@ static void test_ota_pending_default_and_roundtrip(void)
|
||||
TEST_ASSERT_EQUAL_UINT8(1, out.ota_pending);
|
||||
}
|
||||
|
||||
/* I6: the writer must place the CRC exactly where the reader looks for it - directly behind
|
||||
* `length` payload bytes. Both sides only agreed by accident while sizeof(nl_settings_t) is a
|
||||
* multiple of 4; one extra uint16_t in the struct used to move the written CRC two bytes past
|
||||
* the read offset, which would have failed every stored record's CRC after an update. This test
|
||||
* nails the invariant independently of the struct size. */
|
||||
static void test_crc_offset_matches_reader(void)
|
||||
{
|
||||
nl_settings_t in = sample("crc"), out;
|
||||
uint16_t length;
|
||||
uint32_t crc, stored;
|
||||
const uint8_t *rec = &fake_flash_mem[NL_FL_SETTINGS_A];
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, nl_settings_save(&in));
|
||||
memcpy(&length, rec + 6, 2); /* header.length */
|
||||
TEST_ASSERT_EQUAL_UINT16(sizeof(nl_settings_t), length);
|
||||
|
||||
crc = nl_crc32(0, rec, 12u + length); /* header + exactly `length` payload bytes */
|
||||
memcpy(&stored, rec + 12u + length, 4); /* where read_rec() takes the CRC from */
|
||||
TEST_ASSERT_EQUAL_HEX32(crc, stored);
|
||||
|
||||
TEST_ASSERT_TRUE(nl_settings_load(&out)); /* and the record really does read back */
|
||||
TEST_ASSERT_EQUAL_MEMORY(&in, &out, sizeof in);
|
||||
}
|
||||
|
||||
static void test_erase(void)
|
||||
{
|
||||
nl_settings_t s = sample("x"), out;
|
||||
@@ -154,6 +178,7 @@ int main(void)
|
||||
RUN_TEST(test_load_accepts_shorter_record);
|
||||
RUN_TEST(test_load_rejects_longer_record);
|
||||
RUN_TEST(test_ota_pending_default_and_roundtrip);
|
||||
RUN_TEST(test_crc_offset_matches_reader);
|
||||
RUN_TEST(test_erase);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user