]> granicus.if.org Git - esp-idf/commitdiff
nvs: check CRC of items on full pages
authorIvan Grokhotkov <ivan@espressif.com>
Mon, 4 Sep 2017 03:54:18 +0000 (11:54 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Mon, 25 Sep 2017 15:49:27 +0000 (23:49 +0800)
Previously NVS did check CRC values of key-value pairs on the active
page, but the check for full pages was missing. This adds the necessary
check and a test for it.

components/nvs_flash/src/nvs_page.cpp
components/nvs_flash/test_nvs_host/test_nvs.cpp

index 8f562dca4f58bc32633a93fdbe752777b9d18b1e..11dcb17d1d373c7a127638575d035c1d37892efb 100644 (file)
@@ -577,6 +577,17 @@ esp_err_t Page::mLoadEntryTable()
             }
 
             mHashList.insert(item, i);
+            
+            if (item.crc32 != item.calculateCrc32()) {
+                err = eraseEntryAndSpan(i);
+                if (err != ESP_OK) {
+                    mState = PageState::INVALID;
+                    return err;
+                }
+                continue;
+            }
+            
+            assert(item.span > 0);
 
             size_t span = item.span;
             i += span - 1;
index 22d4c3b70bc52b00cb0eef553837606fa2e83472..d4ec585ed7280a6e9051b5c975f6028820a85ff8 100644 (file)
@@ -1096,6 +1096,44 @@ TEST_CASE("recovery after failure to write data", "[nvs]")
     }
 }
 
+TEST_CASE("crc errors in item header are handled", "[nvs]")
+{
+    SpiFlashEmulator emu(3);
+    Storage storage;
+    // prepare some data
+    TEST_ESP_OK(storage.init(0, 3));
+    TEST_ESP_OK(storage.writeItem(0, "ns1", static_cast<uint8_t>(1)));
+    TEST_ESP_OK(storage.writeItem(1, "value1", static_cast<uint32_t>(1)));
+    TEST_ESP_OK(storage.writeItem(1, "value2", static_cast<uint32_t>(2)));
+    
+    // corrupt item header
+    uint32_t val = 0;
+    emu.write(32 * 3, &val, 4);
+    
+    // check that storage can recover
+    TEST_ESP_OK(storage.init(0, 3));
+    TEST_ESP_OK(storage.readItem(1, "value2", val));
+    CHECK(val == 2);
+    // check that the corrupted item is no longer present
+    TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value1", val));
+    
+    // add more items to make the page full
+    for (size_t i = 0; i < Page::ENTRY_COUNT; ++i) {
+        char item_name[Item::MAX_KEY_LENGTH + 1];
+        snprintf(item_name, sizeof(item_name), "item_%ld", i);
+        TEST_ESP_OK(storage.writeItem(1, item_name, static_cast<uint32_t>(i)));
+    }
+
+    // corrupt another item on the full page
+    val = 0;
+    emu.write(32 * 4, &val, 4);
+    
+    // check that storage can recover
+    TEST_ESP_OK(storage.init(0, 3));
+    // check that the corrupted item is no longer present
+    TEST_ESP_ERR(ESP_ERR_NVS_NOT_FOUND, storage.readItem(1, "value2", val));
+}
+
 TEST_CASE("crc error in variable length item is handled", "[nvs]")
 {
     SpiFlashEmulator emu(3);