From 67446df8c9afe757a15aa19d0f05576f1c689b8a Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Mon, 14 Oct 2024 16:31:37 +0700
Subject: [PATCH] Chain loading checks refined

---
 modules/chain/dap_chain_cell.c | 43 ++++++++++++++++++----------------
 1 file changed, 23 insertions(+), 20 deletions(-)

diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index ba76d6f825..58817574d9 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -412,11 +412,10 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
 {
     if (!a_cell)
         return -1;
-    off_t l_ssize = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
-    if (l_ssize < 0)
+    off_t l_full_size = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
+    if (l_full_size < 0)
         return log_it(L_ERROR, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno)), -1;
-    size_t l_full_size = (size_t)l_ssize;
-    if ( l_full_size < sizeof(dap_chain_cell_file_header_t) ) {
+    if ( l_full_size < (off_t)sizeof(dap_chain_cell_file_header_t) ) {
         log_it(L_ERROR, "Chain cell \"%s\" is corrupt, create new file", a_cell->file_storage_path);
         return -1;
     }
@@ -445,7 +444,7 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
         if (!a_chain->is_mapped) DAP_DELETE(l_hdr);
         return -4;
     }
-    size_t l_pos = sizeof(dap_chain_cell_file_header_t);
+    off_t l_pos = sizeof(*l_hdr);
     if (a_chain->is_mapped)
         a_cell->map_pos = a_cell->map + l_pos;
     if (l_full_size == l_pos) {
@@ -453,23 +452,21 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
     }
 
     int l_ret = 0;    
-    uint64_t l_el_size, q = 0;
+    uint64_t l_el_size = 0, q = 0;
     if (a_chain->is_mapped) {
-        uint64_t l_vol_rest;
         dap_hash_fast_t l_atom_hash;
-        for ( l_el_size = 0; l_pos < l_full_size; ++q, l_pos += l_el_size + sizeof(uint64_t) ) {
-            l_vol_rest = (uint64_t)( a_cell->map_end - a_cell->map_pos );
-            if ( l_vol_rest <= sizeof(uint64_t) || l_vol_rest - sizeof(uint64_t) <= *(uint64_t*)a_cell->map_pos)
-                if ( s_cell_map_new_volume(a_cell, l_pos, true) )
+        for ( off_t l_vol_rest = 0; l_pos + sizeof(uint64_t) < l_full_size; ++q, l_pos += l_el_size + sizeof(uint64_t) ) {
+            l_vol_rest = (off_t)(a_cell->map_end - a_cell->map_pos) - sizeof(uint64_t);
+            if ( l_vol_rest <= 0 || (uint64_t)l_vol_rest < *(uint64_t*)a_cell->map_pos )
+                if ( s_cell_map_new_volume(a_cell, l_pos, true) ) {
+                    l_ret = -2;
                     break;
-            if (*(uint64_t*)a_cell->map_pos > l_full_size - l_pos ) {
-                log_it(L_ERROR, "Atom size exeeds file remainder: %zu > %zu. "
-                                "Truncating chain \"%s\"", l_el_size, l_full_size - l_pos, a_cell->file_storage_path );
-                ftruncate(fileno(a_cell->file_storage), l_pos);
-                break;
-            }
+                }
             l_el_size = *(uint64_t*)a_cell->map_pos;
-            dap_chain_atom_ptr_t l_atom = (dap_chain_atom_ptr_t)(a_cell->map_pos += sizeof(uint64_t));
+            if ( l_el_size > (size_t)(l_full_size - l_pos) )
+                break;
+            a_cell->map_pos += sizeof(uint64_t);
+            dap_chain_atom_ptr_t l_atom = (dap_chain_atom_ptr_t)(a_cell->map_pos);
             dap_hash_fast(l_atom, l_el_size, &l_atom_hash);
             a_chain->callback_atom_add(a_chain, l_atom, l_el_size, &l_atom_hash, false);
             a_cell->map_pos += l_el_size;
@@ -493,14 +490,15 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
                 l_ret = -5;
                 break;
             }
-            l_pos += sizeof(uint64_t) + ( l_read = fread((void*)l_element, 1, l_el_size, a_cell->file_storage) );
-            a_chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
+            l_read = fread((void*)l_element, 1, l_el_size, a_cell->file_storage);
             if (l_read != l_el_size) {
                 log_it(L_ERROR, "Read only %lu of %zu bytes, stop cell loading", l_read, l_el_size);
                 DAP_DELETE(l_element);
                 l_ret = -6;
                 break;
             }
+            l_pos += sizeof(uint64_t) + l_read;
+            a_chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
             dap_hash_fast_t l_atom_hash = {};
             dap_hash_fast(l_element, l_el_size, &l_atom_hash);
             dap_chain_atom_verify_res_t l_res = a_chain->callback_atom_add(a_chain, l_element, l_el_size, &l_atom_hash, false);
@@ -510,6 +508,11 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
             ++q;
         }
     }
+    if ( l_pos < l_full_size ) {
+        log_it(L_ERROR, "Chain \"%s\" has incomplete tail, truncating %zu bytes",
+                        a_cell->file_storage_path, l_full_size - l_pos );
+        ftruncate(fileno(a_cell->file_storage), l_pos);
+    }
     fseeko(a_cell->file_storage, l_pos, SEEK_SET);
     log_it(L_INFO, "Loaded %lu atoms in cell %s", q, a_cell->file_storage_path);
     return l_ret;
-- 
GitLab