]> Kevux Git Server - fll/commitdiff
Security: Invalid write in FSS functions and ensure a reset used length on error.
authorKevin Day <thekevinday@gmail.com>
Sat, 10 Dec 2022 16:28:24 +0000 (10:28 -0600)
committerKevin Day <thekevinday@gmail.com>
Sat, 10 Dec 2022 16:28:24 +0000 (10:28 -0600)
The command that triggers this is "fss_basic_write -oc hi there".

An invalid write is happening due to not always performing the array size increase operations.
Update all FSS write functions with more thorough checks.
This problem is being obfuscated by the lossy allocation.

When errors happen the destination->used needs to be consistently reset to the original value on return.

Use the lossy allocation as well for allocation shwere the increase by is a raw digit.
In these specific cases use state.step_small rather than state.step_large.

Rename used_start to destination_used for improved consistency.

level_1/fl_fss/c/fss/basic.c
level_1/fl_fss/c/fss/basic_list.c
level_1/fl_fss/c/fss/embedded_list.c
level_1/fl_fss/c/fss/extended.c
level_1/fl_fss/c/fss/extended_list.c
level_1/fl_fss/c/private-fss.c

index 9b0481c17386d3173c8dd59130e87733afdecb43..2765896634379313bbb1b65d4eaf731e763f3bea 100644 (file)
@@ -88,10 +88,6 @@ extern "C" {
       return F_data_not_eos;
     }
 
-    // Ensure that there is room for the potential terminating newline.
-    status = f_string_dynamic_increase_by(2, destination);
-    if (F_status_is_error(status)) return status;
-
     const f_array_length_t destination_used = destination->used;
 
     for (; range->start <= range->stop && range->start < content.used; ++range->start) {
@@ -110,10 +106,26 @@ extern "C" {
 
       if (content.string[range->start] == f_fss_placeholder_s.string[0]) continue;
 
+      status = f_string_dynamic_increase(state.step_large, destination);
+
+      if (F_status_is_error(status)) {
+        destination->used = destination_used;
+
+        return status;
+      }
+
       destination->string[destination->used++] = content.string[range->start];
     } // for
 
     if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
+      status = f_string_dynamic_increase(state.step_large, destination);
+
+      if (F_status_is_error(status)) {
+        destination->used = destination_used;
+
+        return status;
+      }
+
       destination->string[destination->used++] = f_fss_basic_close_s.string[0];
     }
 
@@ -154,15 +166,23 @@ extern "C" {
 
     f_status_t status = private_fl_fss_basic_write(F_true, object, quote ? quote : f_fss_quote_double_s.string[0], state, range, destination);
 
+    if (F_status_is_error(status)) {
+      destination->used = destination_used;
+
+      return status;
+    }
+
     if (status == F_data_not_stop || status == F_data_not_eos) {
 
       // Objects cannot be empty, so write a quote empty string.
-      const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
+      {
+        const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
 
-      if (F_status_is_error(status_allocation)) {
-        destination->used = destination_used;
+        if (F_status_is_error(status_allocation)) {
+          destination->used = destination_used;
 
-        return status_allocation;
+          return status_allocation;
+        }
       }
 
       destination->string[destination->used++] = quote ? quote : f_fss_quote_double_s.string[0];
index ccb10c18c795923654a3f02fbb44bf3a258c4988..89c4228aa3232b51cedc941a194782df7516021f 100644 (file)
@@ -313,10 +313,10 @@ extern "C" {
     }
 
     // Ensure that there is room for a slash delimit and possibly the end of content character.
-    status = f_string_dynamic_increase_by(3, destination);
+    status = f_string_dynamic_increase_by(state.step_small + 3, destination);
     if (F_status_is_error(status)) return status;
 
-    const f_array_length_t used_start = destination->used;
+    const f_array_length_t destination_used = destination->used;
 
     bool is_comment = F_false;
     bool has_graph = F_false;
@@ -359,15 +359,23 @@ extern "C" {
             status = state.interrupt((void *) &state, 0);
 
             if (F_status_set_fine(status) == F_interrupt) {
-              status = F_status_set_error(F_interrupt);
+              destination->used = destination_used;
 
-              break;
+              return F_status_set_error(F_interrupt);
             }
           }
 
           if (content.string[range->start] == f_fss_placeholder_s.string[0]) continue;
           if (content.string[range->start] != f_fss_slash_s.string[0]) break;
 
+          status = f_string_dynamic_increase(state.step_large, destination);
+
+          if (F_status_is_error(status)) {
+            destination->used = destination_used;
+
+            return status;
+          }
+
           destination->string[destination->used++] = f_fss_slash_s.string[0];
           ++slash_count;
         } // for
@@ -426,7 +434,7 @@ extern "C" {
         if (content.string[range->start] == f_fss_eol_s.string[0] || range->start >= content.used || range->start > range->stop) {
 
           // Increase by slash and basic list open and possible newline.
-          status = f_string_dynamic_increase_by(3, destination);
+          status = f_string_dynamic_increase_by(state.step_small + 3, destination);
           if (F_status_is_error(status)) break;
 
           destination->string[destination->used++] = f_fss_slash_s.string[0];
@@ -493,14 +501,19 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
 
     if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
       status = f_string_dynamic_increase(state.step_large, destination);
-      if (F_status_is_error(status)) return status;
+
+      if (F_status_is_error(status)) {
+        destination->used = destination_used;
+
+        return status;
+      }
 
       // Check to see if a newline exists, at the end.
       if (destination->used) {
@@ -785,8 +798,10 @@ extern "C" {
 
     if (status == F_none_stop || status == F_none_eos) {
       if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e) {
-        const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
-        if (F_status_is_error(status_allocation)) return status_allocation;
+        {
+          const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
+          if (F_status_is_error(status_allocation)) return status_allocation;
+        }
 
         destination->string[destination->used++] = f_fss_basic_list_open_s.string[0];
 
@@ -800,11 +815,7 @@ extern "C" {
       return F_data_not_eos;
     }
 
-    // Ensure that there is room for a slash delimit, the object open character, and the end of line character.
-    status = f_string_dynamic_increase_by(4, destination);
-    if (F_status_is_error(status)) return status;
-
-    const f_array_length_t used_start = destination->used;
+    const f_array_length_t destination_used = destination->used;
 
     f_array_length_t i = 0;
     f_array_length_t slash_count = 0;
@@ -874,7 +885,7 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
@@ -952,26 +963,26 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
 
     if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e) {
       if (complete == f_fss_complete_full_trim_e) {
-        status = private_fl_fss_basic_list_write_object_trim(used_start, state, destination);
+        status = private_fl_fss_basic_list_write_object_trim(destination_used, state, destination);
 
         if (F_status_is_error(status)) {
-          destination->used = used_start;
+          destination->used = destination_used;
 
           return status;
         }
       }
 
-      status = f_string_dynamic_increase_by(2, destination);
+      status = f_string_dynamic_increase(state.step_small + 2, destination);
 
       if (F_status_is_error(status)) {
-        destination->used = used_start;
+        destination->used = destination_used;
 
         return status;
       }
index 58bc729f7a173505497148e0f5e03011eb7f2b17..cae62613d6afc1d828251a2847b77b0c00ecf92b 100644 (file)
@@ -688,7 +688,7 @@ extern "C" {
 
     if (range->start > range->stop || range->start >= content.used) {
       if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
-        const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
+        const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
         if (F_status_is_error(status_allocation)) return status_allocation;
 
         destination->string[destination->used++] = f_fss_embedded_list_close_s.string[0];
@@ -698,11 +698,7 @@ extern "C" {
       return status;
     }
 
-    // Ensure that there is room for a slash delimit and possibly the end of content characters.
-    status = f_string_dynamic_increase_by(4, destination);
-    if (F_status_is_error(status)) return status;
-
-    const f_array_length_t used_start = destination->used;
+    const f_array_length_t destination_used = destination->used;
 
     bool is_comment = F_false;
     bool ends_on_eol = F_false;
@@ -739,6 +735,9 @@ extern "C" {
           do_prepend = F_false;
         }
 
+        status = f_string_dynamic_increase(state.step_large, destination);
+        if (F_status_is_error(status)) break;
+
         destination->string[destination->used++] = content.string[range->start];
 
         for (++range->start; range->start <= range->stop && range->start < content.used; ++range->start) {
@@ -747,15 +746,23 @@ extern "C" {
             status = state.interrupt((void *) &state, 0);
 
             if (F_status_set_fine(status) == F_interrupt) {
-              status = F_status_set_error(F_interrupt);
+              destination->used = destination_used;
 
-              break;
+              return F_status_set_error(F_interrupt);
             }
           }
 
           if (content.string[range->start] == f_fss_placeholder_s.string[0]) continue;
           if (content.string[range->start] != f_fss_slash_s.string[0]) break;
 
+          status = f_string_dynamic_increase(state.step_large, destination);
+
+          if (F_status_is_error(status)) {
+            destination->used = destination_used;
+
+            return status;
+          }
+
           destination->string[destination->used++] = f_fss_slash_s.string[0];
           ++slash_count;
         } // for
@@ -794,7 +801,7 @@ extern "C" {
           }
 
           // Increase by character at "start" and possible newline.
-          status = f_string_dynamic_increase_by(2, destination);
+          status = f_string_dynamic_increase_by(state.step_small + 2, destination);
           if (F_status_is_error(status)) break;
 
           destination->string[destination->used++] = content.string[start];
@@ -855,7 +862,7 @@ extern "C" {
           }
 
           // Increase by slash and extended list open and possible newline.
-          status = f_string_dynamic_increase_by(3, destination);
+          status = f_string_dynamic_increase_by(state.step_small + 3, destination);
           if (F_status_is_error(status)) break;
 
           destination->string[destination->used++] = f_fss_slash_s.string[0];
@@ -922,13 +929,13 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
 
     if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
-      status = f_string_dynamic_increase_by(3, destination);
+      status = f_string_dynamic_increase_by(state.step_small + 3, destination);
       if (F_status_is_error(status)) return status;
 
       if (!ends_on_eol) {
@@ -1248,8 +1255,10 @@ extern "C" {
 
     if (status == F_data_not_stop || status == F_data_not_eos) {
       if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e) {
-        const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
-        if (F_status_is_error(status_allocation)) return status_allocation;
+        {
+          const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
+          if (F_status_is_error(status_allocation)) return status_allocation;
+        }
 
         destination->string[destination->used++] = f_fss_embedded_list_open_s.string[0];
 
@@ -1262,10 +1271,10 @@ extern "C" {
     }
 
     // Ensure that there is room for a slash delimit, the object open character, and the end of line character.
-    status = f_string_dynamic_increase_by(4, destination);
+    status = f_string_dynamic_increase_by(state.step_small + 4, destination);
     if (F_status_is_error(status)) return status;
 
-    const f_array_length_t used_start = destination->used;
+    const f_array_length_t destination_used = destination->used;
 
     f_array_length_t i = 0;
     f_array_length_t slash_count = 0;
@@ -1337,7 +1346,7 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
@@ -1363,9 +1372,9 @@ extern "C" {
             status = state.interrupt((void *) &state, 0);
 
             if (F_status_set_fine(status) == F_interrupt) {
-              status = F_status_set_error(F_interrupt);
+              destination->used = destination_used;
 
-              break;
+              return F_status_set_error(F_interrupt);
             }
           }
 
@@ -1375,8 +1384,6 @@ extern "C" {
           ++slash_count;
         } // for
 
-        if (F_status_is_error(status)) break;
-
         if (range->start > range->stop || range->start >= object.used) {
 
           // Slashes at the end of the object must be delimited to avoid delimiting the object close character.
@@ -1430,17 +1437,17 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
 
     if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e) {
       if (complete == f_fss_complete_full_trim_e) {
-        status = private_fl_fss_basic_list_write_object_trim(used_start, state, destination);
+        status = private_fl_fss_basic_list_write_object_trim(destination_used, state, destination);
 
         if (F_status_is_error(status)) {
-          destination->used = used_start;
+          destination->used = destination_used;
 
           return status;
         }
@@ -1449,10 +1456,10 @@ extern "C" {
         ends_on_space = F_true;
       }
 
-      status = f_string_dynamic_increase_by(3, destination);
+      status = f_string_dynamic_increase_by(state.step_small + 3, destination);
 
       if (F_status_is_error(status)) {
-        destination->used = used_start;
+        destination->used = destination_used;
 
         return status;
       }
index bf84328681fd1ecc278724044b58d81ce91f9564..488820602a536d1eb427ce572be41a6ccabe4342 100644 (file)
@@ -135,14 +135,24 @@ extern "C" {
       if (!destination) return F_status_set_error(F_parameter);
     #endif // _di_level_1_parameter_checking_
 
+    const f_array_length_t destination_used = destination->used;
+
     // This operates exactly like an object, syntax-wise.
     const f_status_t status = private_fl_fss_basic_write(F_false, content, quote ? quote : f_fss_quote_double_s.string[0], state, range, destination);
 
+    if (F_status_is_error(status)) {
+      destination->used = destination_used;
+
+      return status;
+    }
+
     if (status == F_data_not_stop || status == F_data_not_eos) {
 
       // Content that is empty must be represented by a quote empty string.
-      const f_status_t status_allocation = f_string_dynamic_increase_by(4, destination);
-      if (F_status_is_error(status_allocation)) return status_allocation;
+      {
+        const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 4, destination);
+        if (F_status_is_error(status_allocation)) return status_allocation;
+      }
 
       destination->string[destination->used++] = quote ? quote : f_fss_quote_double_s.string[0];
       destination->string[destination->used++] = quote ? quote : f_fss_quote_double_s.string[0];
@@ -161,17 +171,18 @@ extern "C" {
       return F_none_eos;
     }
 
-    if (F_status_is_error_not(status)) {
-      const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
+    // Ensure that there is room, including the slash delimit and possibly the end of content characters.
+    {
+      const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
       if (F_status_is_error(status_allocation)) return status_allocation;
+    }
 
-      if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_next_e) {
-        destination->string[destination->used++] = f_fss_extended_next_s.string[0];
-      }
+    if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_next_e) {
+      destination->string[destination->used++] = f_fss_extended_next_s.string[0];
+    }
 
-      if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
-        destination->string[destination->used++] = f_fss_extended_close_s.string[0];
-      }
+    if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
+      destination->string[destination->used++] = f_fss_extended_close_s.string[0];
     }
 
     return status;
@@ -205,15 +216,28 @@ f_status_t fl_fss_extended_object_write(const f_string_static_t object, const ui
       if (!destination) return F_status_set_error(F_parameter);
     #endif // _di_level_1_parameter_checking_
 
-    const f_array_length_t used_start = destination->used;
+    const f_array_length_t destination_used = destination->used;
 
     f_status_t status = private_fl_fss_basic_write(F_true, object, quote ? quote : f_fss_quote_double_s.string[0], state, range, destination);
 
+    if (F_status_is_error(status)) {
+      destination->used = destination_used;
+
+      return status;
+    }
+
     if (status == F_data_not_stop || status == F_data_not_eos) {
 
       // Objects cannot be empty, so write a quote empty string.
-      const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
-      if (F_status_is_error(status_allocation)) return status_allocation;
+      {
+        const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
+
+        if (F_status_is_error(status_allocation)) {
+          destination->used = destination_used;
+
+          return status_allocation;
+        }
+      }
 
       destination->string[destination->used++] = quote ? quote : f_fss_quote_double_s.string[0];
       destination->string[destination->used++] = quote ? quote : f_fss_quote_double_s.string[0];
@@ -224,12 +248,22 @@ f_status_t fl_fss_extended_object_write(const f_string_static_t object, const ui
         f_status_t status2 = F_none;
 
         if (complete == f_fss_complete_full_trim_e) {
-          status2 = private_fl_fss_basic_write_object_trim(quote ? quote : f_fss_quote_double_s.string[0], used_start, state, destination);
-          if (F_status_is_error(status2)) return status2;
+          status2 = private_fl_fss_basic_write_object_trim(quote ? quote : f_fss_quote_double_s.string[0], destination_used, state, destination);
+
+          if (F_status_is_error(status2)) {
+            destination->used = destination_used;
+
+            return status2;
+          }
         }
 
         status2 = f_string_dynamic_increase(state.step_large, destination);
-        if (F_status_is_error(status2)) return status2;
+
+        if (F_status_is_error(status2)) {
+          destination->used = destination_used;
+
+          return status2;
+        }
 
         destination->string[destination->used++] = f_fss_extended_open_s.string[0];
       }
index 98f6ac0630fc6578713be4b7c2d4f8eaf7f5c1c7..653dd0508b8f9b9589481479b9219e93f3adacfc 100644 (file)
@@ -241,8 +241,10 @@ extern "C" {
 
     if (range->start > range->stop || range->start >= content.used) {
       if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
-        const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
-        if (F_status_is_error(status_allocation)) return status_allocation;
+        {
+          const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
+          if (F_status_is_error(status_allocation)) return status_allocation;
+        }
 
         destination->string[destination->used++] = f_fss_extended_list_close_s.string[0];
         destination->string[destination->used++] = f_fss_extended_list_close_end_s.string[0];
@@ -252,10 +254,10 @@ extern "C" {
     }
 
     // Ensure that there is room for a slash delimit and possibly the end of content characters.
-    status = f_string_dynamic_increase_by(4, destination);
+    status = f_string_dynamic_increase_by(state.step_small + 4, destination);
     if (F_status_is_error(status)) return status;
 
-    const f_array_length_t used_start = destination->used;
+    const f_array_length_t destination_used = destination->used;
 
     bool is_comment = F_false;
     bool ends_on_eol = F_false;
@@ -263,11 +265,10 @@ extern "C" {
     bool do_prepend = prepend ? F_true : F_false;
 
     f_array_length_t i = 0;
+    f_array_length_t r = 0;
     f_array_length_t slash_count = 0;
     f_array_length_t start = 0;
 
-    f_array_length_t r = 0;
-
     uint8_t width = 0;
 
     while (range->start <= range->stop && range->start < content.used) {
@@ -286,11 +287,18 @@ extern "C" {
         slash_count = 1;
 
         if (do_prepend) {
+          status = f_string_dynamic_increase_by(state.step_small + prepend->used, destination);
+          if (F_status_is_error(status)) break;
+
           status = f_string_dynamic_append(*prepend, destination);
           if (F_status_is_error(status)) break;
 
           do_prepend = F_false;
         }
+        else {
+          status = f_string_dynamic_increase(state.step_large, destination);
+          if (F_status_is_error(status)) break;
+        }
 
         destination->string[destination->used++] = content.string[range->start];
 
@@ -300,15 +308,23 @@ extern "C" {
             status = state.interrupt((void *) &state, 0);
 
             if (F_status_set_fine(status) == F_interrupt) {
-              status = F_status_set_error(F_interrupt);
+              destination->used = destination_used;
 
-              break;
+              return F_status_set_error(F_interrupt);
             }
           }
 
           if (content.string[range->start] == f_fss_placeholder_s.string[0]) continue;
           if (content.string[range->start] != f_fss_slash_s.string[0]) break;
 
+          status = f_string_dynamic_increase(state.step_large, destination);
+
+          if (F_status_is_error(status)) {
+            destination->used = destination_used;
+
+            return status;
+          }
+
           destination->string[destination->used++] = f_fss_slash_s.string[0];
           ++slash_count;
         } // for
@@ -323,9 +339,7 @@ extern "C" {
             // Do nothing.
           }
           else if (content.string[range->start] == f_fss_eol_s.string[0] || range->start >= content.used || range->start > range->stop) {
-
-            // increase by total slashes + 1 and extended list close.
-            status = f_string_dynamic_increase_by(2, destination);
+            status = f_string_dynamic_increase_by(state.step_small + 2, destination);
             if (F_status_is_error(status)) break;
 
             destination->string[destination->used++] = f_fss_slash_s.string[0];
@@ -344,7 +358,7 @@ extern "C" {
           }
 
           // Increase by character at "start" and possible newline.
-          status = f_string_dynamic_increase_by(2, destination);
+          status = f_string_dynamic_increase_by(state.step_small + 2, destination);
           if (F_status_is_error(status)) break;
 
           destination->string[destination->used++] = content.string[start];
@@ -405,7 +419,7 @@ extern "C" {
           }
 
           // Increase by slash and extended list close.
-          status = f_string_dynamic_increase_by(2, destination);
+          status = f_string_dynamic_increase_by(state.step_small + 2, destination);
           if (F_status_is_error(status)) break;
 
           destination->string[destination->used++] = f_fss_slash_s.string[0];
@@ -472,14 +486,18 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
 
     if (complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e || complete == f_fss_complete_end_e) {
-      status = f_string_dynamic_increase_by(3, destination);
-      if (F_status_is_error(status)) return status;
+      status = f_string_dynamic_increase_by(state.step_small + 3, destination);
+      if (F_status_is_error(status)) {
+        destination->used = destination_used;
+
+        return status;
+      }
 
       if (!ends_on_eol) {
         destination->string[destination->used++] = f_fss_eol_s.string[0];
@@ -798,8 +816,10 @@ extern "C" {
 
     if (status == F_data_not_stop || status == F_data_not_eos) {
       if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e) {
-        const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
-        if (F_status_is_error(status_allocation)) return status_allocation;
+        {
+          const f_status_t status_allocation = f_string_dynamic_increase_by(state.step_small + 2, destination);
+          if (F_status_is_error(status_allocation)) return status_allocation;
+        }
 
         destination->string[destination->used++] = f_fss_extended_list_open_s.string[0];
 
@@ -812,10 +832,10 @@ extern "C" {
     }
 
     // Ensure that there is room for a slash delimit, the object open character, and the end of line character.
-    status = f_string_dynamic_increase_by(4, destination);
+    status = f_string_dynamic_increase_by(state.step_small + 4, destination);
     if (F_status_is_error(status)) return status;
 
-    const f_array_length_t used_start = destination->used;
+    const f_array_length_t destination_used = destination->used;
 
     f_array_length_t i = 0;
     f_array_length_t slash_count = 0;
@@ -887,7 +907,7 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
@@ -913,9 +933,9 @@ extern "C" {
             status = state.interrupt((void *) &state, 0);
 
             if (F_status_set_fine(status) == F_interrupt) {
-              status = F_status_set_error(F_interrupt);
+              destination->used = destination_used;
 
-              break;
+              return F_status_set_error(F_interrupt);
             }
           }
 
@@ -925,8 +945,6 @@ extern "C" {
           ++slash_count;
         } // for
 
-        if (F_status_is_error(status)) break;
-
         if (range->start > range->stop || range->start >= object.used) {
 
           // Slashes at the end of the object must be delimited to avoid delimiting the object close character.
@@ -980,17 +998,17 @@ extern "C" {
     } // while
 
     if (F_status_is_error(status)) {
-      destination->used = used_start;
+      destination->used = destination_used;
 
       return status;
     }
 
     if (complete == f_fss_complete_partial_e || complete == f_fss_complete_partial_trim_e || complete == f_fss_complete_full_e || complete == f_fss_complete_full_trim_e) {
       if (complete == f_fss_complete_full_trim_e) {
-        status = private_fl_fss_basic_list_write_object_trim(used_start, state, destination);
+        status = private_fl_fss_basic_list_write_object_trim(destination_used, state, destination);
 
         if (F_status_is_error(status)) {
-          destination->used = used_start;
+          destination->used = destination_used;
 
           return status;
         }
@@ -999,10 +1017,10 @@ extern "C" {
         ends_on_space = F_true;
       }
 
-      status = f_string_dynamic_increase_by(3, destination);
+      status = f_string_dynamic_increase_by(state.step_small + 3, destination);
 
       if (F_status_is_error(status)) {
-        destination->used = used_start;
+        destination->used = destination_used;
 
         return status;
       }
index 53a69e7ba58eb6ab632596967e33f127a95a3571..9941b41859c3f16df8561b88cf4d4d615c4ec1bf 100644 (file)
@@ -700,7 +700,7 @@ extern "C" {
     if (status == F_data_not) return status;
 
     // Ensure that there is room for the potential start and stop quotes, a potential delimit at start, and the potential object open character.
-    status = f_string_dynamic_increase_by(5, destination);
+    status = f_string_dynamic_increase_by(state.step_small + 5, destination);
     if (F_status_is_error(status)) return status;
 
     const f_array_length_t input_start = range->start;
@@ -807,7 +807,7 @@ extern "C" {
           item_first = range->start++;
 
           status = f_fss_skip_past_delimit(state, object, range);
-          if (F_status_is_error(status)) return status;
+          if (F_status_is_error(status)) break;
 
           if (range->start > range->stop || range->start >= object.used) {
 
@@ -836,20 +836,14 @@ extern "C" {
 
             quoted_is = F_true;
 
-            status = f_string_dynamic_increase_by(item_total, destination);
+            status = f_string_dynamic_increase_by(item_total + 1, destination);
             if (F_status_is_error(status)) break;
 
             // Add the slashes that delimit the slashes.
             if (item_first == input_start) {
-              status = f_string_dynamic_increase(state.step_large, destination);
-              if (F_status_is_error(status)) break;
-
               destination->string[destination->used++] = f_fss_slash_s.string[0];
             }
             else {
-              status = f_string_dynamic_increase_by(item_total, destination);
-              if (F_status_is_error(status)) break;
-
               for (i = 0; i < item_total; ++i) {
                 destination->string[destination->used++] = f_fss_slash_s.string[0];
               } // for
@@ -915,9 +909,6 @@ extern "C" {
             destination->string[destination->used++] = f_fss_slash_s.string[0];
           } // for
 
-          status = f_string_dynamic_increase_by(width, destination);
-          if (F_status_is_error(status)) break;
-
           for (i = 0; i < width; ++i) {
             destination->string[destination->used++] = object.string[range->start + i];
           } // for
@@ -980,7 +971,7 @@ extern "C" {
 
         width = macro_f_utf_byte_width(object.string[range->start]);
 
-        status = f_string_dynamic_increase_by(1 + width, destination);
+        status = f_string_dynamic_increase_by(width + 1, destination);
         if (F_status_is_error(status)) break;
 
         destination->string[destination->used++] = quote_char;
@@ -1025,7 +1016,7 @@ extern "C" {
     }
 
     if (quoted_is) {
-      status = f_string_dynamic_increase(state.step_large, destination);
+      status = f_string_dynamic_increase_by(state.step_small + 2, destination);
 
       if (F_status_is_error(status)) {
         destination->used = used_start;
@@ -1045,6 +1036,8 @@ extern "C" {
             status = state.interrupt((void *) &state, 0);
 
             if (F_status_set_fine(status) == F_interrupt) {
+              destination->used = used_start;
+
               return F_status_set_error(F_interrupt);
             }
           }
@@ -1083,9 +1076,7 @@ extern "C" {
       destination->string[used_start] = f_fss_slash_s.string[0];
     }
 
-    if (range->start > range->stop) {
-      return F_none_stop;
-    }
+    if (range->start > range->stop) return F_none_stop;
 
     return F_none_eos;
   }