]> 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:53:34 +0000 (10:53 -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 610848ed63cc736f4b7be3e6cad8c0fbcaed0404..e82e4103f5f4f7b7efbf575dd462ab332b9abed3 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_delimit_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_delimit_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 quoted empty string.
-      const f_status_t status_allocation = f_string_dynamic_increase_by(2, destination);
+      // Objects cannot be empty, so write a quote empty string.
+      {
+        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 ? f_fss_delimit_quote_single_s.string[0] : f_fss_delimit_quote_double_s.string[0];
index ff31dd35281bbf9ffeaff3b8d13b1c815d39ce40..f19a48d11ac639fb1d7b39e0deab033db3db611a 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_delimit_placeholder_s.string[0]) continue;
           if (content.string[range->start] != f_fss_delimit_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_delimit_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_delimit_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 ba0230b5b31fff2dda6e1194a8421fee556db2be..cc568b271c59cefe3a9dc483ead89dfbd24d9bd4 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_delimit_placeholder_s.string[0]) continue;
           if (content.string[range->start] != f_fss_delimit_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_delimit_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_delimit_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 bc1d8c7ee917188294ba596025cb692d3caf1118..56d5a17ae035c7f7f96f4169c830ae2332be9628 100644 (file)
@@ -132,14 +132,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_delimit_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 ? f_fss_delimit_quote_single_s.string[0] : f_fss_delimit_quote_double_s.string[0];
       destination->string[destination->used++] = quote ? f_fss_delimit_quote_single_s.string[0] : f_fss_delimit_quote_double_s.string[0];
@@ -158,17 +168,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;
@@ -202,15 +213,28 @@ f_status_t fl_fss_extended_object_write(const f_string_static_t object, const f_
       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_delimit_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 ? f_fss_delimit_quote_single_s.string[0] : f_fss_delimit_quote_double_s.string[0];
       destination->string[destination->used++] = quote ? f_fss_delimit_quote_single_s.string[0] : f_fss_delimit_quote_double_s.string[0];
@@ -221,12 +245,22 @@ f_status_t fl_fss_extended_object_write(const f_string_static_t object, const f_
         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_delimit_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_delimit_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 9e30b75c0e29b086e4bee0dfaaaa6f0bbd2da460..8f2bfd597a25838548cffa97160df1b42b4894fd 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_delimit_placeholder_s.string[0]) continue;
           if (content.string[range->start] != f_fss_delimit_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_delimit_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_delimit_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_delimit_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 25ae62115348ce49140e20d4e721ba182a5444ba..c25535fadb5b9713690e430ebc93d9be525f12b3 100644 (file)
@@ -706,7 +706,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;
@@ -813,7 +813,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) {
 
@@ -842,20 +842,14 @@ extern "C" {
 
             quote_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_delimit_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_delimit_slash_s.string[0];
               } // for
@@ -921,9 +915,6 @@ extern "C" {
             destination->string[destination->used++] = f_fss_delimit_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
@@ -986,7 +977,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;
@@ -1031,7 +1022,7 @@ extern "C" {
     }
 
     if (quote_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;
@@ -1051,6 +1042,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);
             }
           }
@@ -1089,9 +1082,7 @@ extern "C" {
       destination->string[used_start] = f_fss_delimit_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;
   }