Repository: nasa/fprime (language: python)

Issue:
Update to FPP v2.1.0a10
* Addresses issue nasa/fpp#407
* Cleans up string code and corrects off-by-one error in buffer sizes
* Refactors code in `Fw::StringBase` that was terse and hard to understand (it was not clear what was going on with serializing and deserializing string lengths; because so much was implicit, it looked like the code was serializing and deserializing null-terminated strings).

**Note:** This PR will require some minor changes in user test code, as discussed in nasa/fpp#409. The changes bring the code more into line with approved C++ standards, by eliminating reliance on implicit conversions. I've made the required changes for the F Prime unit tests in this PR.


Discussion / hints:

Fix patch:
diff --git a/Fw/Cmd/CmdString.hpp b/Fw/Cmd/CmdString.hpp
index 8b8480c34b..9724ce3379 100644
--- a/Fw/Cmd/CmdString.hpp
+++ b/Fw/Cmd/CmdString.hpp
@@ -19,16 +19,16 @@ class CmdStringArg final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_CMD_STR,
         STRING_SIZE = FW_CMD_STRING_MAX_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE),
     };
 
     CmdStringArg() : StringBase() { *this = ""; }
 
-    CmdStringArg(const CmdStringArg& src) : StringBase() { *this = src; }
+    explicit CmdStringArg(const CmdStringArg& src) : StringBase() { *this = src; }
 
-    CmdStringArg(const StringBase& src) : StringBase() { *this = src; }
+    explicit CmdStringArg(const StringBase& src) : StringBase() { *this = src; }
 
-    CmdStringArg(const char* src) : StringBase() { *this = src; }
+    explicit CmdStringArg(const char* src) : StringBase() { *this = src; }
 
     ~CmdStringArg() {}
 
@@ -52,7 +52,7 @@ class CmdStringArg final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[CmdStringArg::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Log/LogString.hpp b/Fw/Log/LogString.hpp
index c348c2fbc3..afa8e26c60 100644
--- a/Fw/Log/LogString.hpp
+++ b/Fw/Log/LogString.hpp
@@ -19,7 +19,7 @@ class LogStringArg final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_LOG_STR,
         STRING_SIZE = FW_LOG_STRING_MAX_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE)
     };
 
     LogStringArg() : StringBase() { *this = ""; }
@@ -52,7 +52,7 @@ class LogStringArg final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[LogStringArg::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Log/TextLogString.hpp b/Fw/Log/TextLogString.hpp
index 70b08281c8..044b6e90e2 100644
--- a/Fw/Log/TextLogString.hpp
+++ b/Fw/Log/TextLogString.hpp
@@ -19,7 +19,7 @@ class TextLogString final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_LOG_STR,
         STRING_SIZE = FW_LOG_TEXT_BUFFER_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE)
     };
 
     TextLogString() : StringBase() { *this = ""; }
@@ -52,7 +52,7 @@ class TextLogString final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[TextLogString::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Prm/PrmBuffer.hpp b/Fw/Prm/PrmBuffer.hpp
index 51b21c94cc..ef97d4f69e 100644
--- a/Fw/Prm/PrmBuffer.hpp
+++ b/Fw/Prm/PrmBuffer.hpp
@@ -16,8 +16,14 @@
 #include <Fw/Types/Serializable.hpp>
 #include <Fw/Cfg/SerIds.hpp>
 
+#include "Fw/Types/StringBase.hpp"
+
+
 namespace Fw {
 
+    static_assert(FW_PARAM_BUFFER_MAX_SIZE >= StringBase::BUFFER_SIZE(FW_PARAM_STRING_MAX_SIZE),
+                  "param string must fit into param buffer");
+
     class ParamBuffer : public SerializeBufferBase {
         public:
 
diff --git a/Fw/Prm/PrmString.hpp b/Fw/Prm/PrmString.hpp
index 3220500568..506228652e 100644
--- a/Fw/Prm/PrmString.hpp
+++ b/Fw/Prm/PrmString.hpp
@@ -19,7 +19,7 @@ class ParamString : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_PRM_STR,
         STRING_SIZE = FW_PARAM_STRING_MAX_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE)
     };
 
     ParamString() : StringBase() { *this = ""; }
@@ -52,7 +52,7 @@ class ParamString : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[ParamString::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Test/String.hpp b/Fw/Test/String.hpp
index 0b08c06d57..191c20d937 100644
--- a/Fw/Test/String.hpp
+++ b/Fw/Test/String.hpp
@@ -18,7 +18,7 @@ class String : public Fw::StringBase {
   public:
     enum {
         STRING_SIZE = 256,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE),
     };
 
     String() : StringBase() { *this = ""; }
@@ -49,7 +49,7 @@ class String : public Fw::StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[String::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Tlm/TlmString.hpp b/Fw/Tlm/TlmString.hpp
index b5d791fc17..5cef8799ec 100644
--- a/Fw/Tlm/TlmString.hpp
+++ b/Fw/Tlm/TlmString.hpp
@@ -19,7 +19,7 @@ class TlmString final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_TLM_STR,
         STRING_SIZE = FW_TLM_STRING_MAX_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE)
     };
 
     TlmString() : StringBase() { *this = ""; }
@@ -52,7 +52,7 @@ class TlmString final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[TlmString::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Types/FileNameString.hpp b/Fw/Types/FileNameString.hpp
index 5234439480..40a16bffb1 100644
--- a/Fw/Types/FileNameString.hpp
+++ b/Fw/Types/FileNameString.hpp
@@ -20,16 +20,16 @@ class FileNameString final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_FILE_NAME_STRING,
         STRING_SIZE = FileNameStringSize,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE)
     };
 
     FileNameString() : StringBase() { *this = ""; }
 
-    FileNameString(const FileNameString& src) : StringBase() { *this = src; }
+    explicit FileNameString(const FileNameString& src) : StringBase() { *this = src; }
 
-    FileNameString(const StringBase& src) : StringBase() { *this = src; }
+    explicit FileNameString(const StringBase& src) : StringBase() { *this = src; }
 
-    FileNameString(const char* src) : StringBase() { *this = src; }
+    explicit FileNameString(const char* src) : StringBase() { *this = src; }
 
     ~FileNameString() {}
 
@@ -53,7 +53,7 @@ class FileNameString final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[FileNameString::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Types/InternalInterfaceString.hpp b/Fw/Types/InternalInterfaceString.hpp
index 7caf3588dc..a81699ed1a 100644
--- a/Fw/Types/InternalInterfaceString.hpp
+++ b/Fw/Types/InternalInterfaceString.hpp
@@ -20,16 +20,16 @@ class InternalInterfaceString final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_INTERNAL_INTERFACE_STRING,
         STRING_SIZE = FW_INTERNAL_INTERFACE_STRING_MAX_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE)
     };
 
     InternalInterfaceString() : StringBase() { *this = ""; }
 
-    InternalInterfaceString(const InternalInterfaceString& src) : StringBase() { *this = src; }
+    explicit InternalInterfaceString(const InternalInterfaceString& src) : StringBase() { *this = src; }
 
-    InternalInterfaceString(const StringBase& src) : StringBase() { *this = src; }
+    explicit InternalInterfaceString(const StringBase& src) : StringBase() { *this = src; }
 
-    InternalInterfaceString(const char* src) : StringBase() { *this = src; }
+    explicit InternalInterfaceString(const char* src) : StringBase() { *this = src; }
 
     ~InternalInterfaceString() {}
 
@@ -53,7 +53,7 @@ class InternalInterfaceString final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[InternalInterfaceString::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Types/ObjectName.hpp b/Fw/Types/ObjectName.hpp
index 1b51c471f7..f255d3fd06 100644
--- a/Fw/Types/ObjectName.hpp
+++ b/Fw/Types/ObjectName.hpp
@@ -19,16 +19,16 @@ class ObjectName final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_OBJECT_NAME,
         STRING_SIZE = FW_OBJ_NAME_MAX_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE)
     };
 
     ObjectName() : StringBase() { *this = ""; }
 
-    ObjectName(const ObjectName& src) : StringBase() { *this = src; }
+    explicit ObjectName(const ObjectName& src) : StringBase() { *this = src; }
 
-    ObjectName(const StringBase& src) : StringBase() { *this = src; }
+    explicit ObjectName(const StringBase& src) : StringBase() { *this = src; }
 
-    ObjectName(const char* src) : StringBase() { *this = src; }
+    explicit ObjectName(const char* src) : StringBase() { *this = src; }
 
     ~ObjectName() {}
 
@@ -52,7 +52,7 @@ class ObjectName final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[ObjectName::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Types/String.hpp b/Fw/Types/String.hpp
index 428fe317f6..38fd4eddb9 100644
--- a/Fw/Types/String.hpp
+++ b/Fw/Types/String.hpp
@@ -19,14 +19,14 @@ class String final : public StringBase {
     enum {
         SERIALIZED_TYPE_ID = FW_TYPEID_FIXED_LENGTH_STRING,
         STRING_SIZE = FW_FIXED_LENGTH_STRING_SIZE,
-        SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType)
+        SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE),
     };
 
     String() : StringBase() { *this = ""; }
 
-    String(const String& src) : StringBase() { *this = src; }
+    explicit String(const String& src) : StringBase() { *this = src; }
 
-    String(const StringBase& src) : StringBase() { *this = src; }
+    explicit String(const StringBase& src) : StringBase() { *this = src; }
 
     String(const char* src) : StringBase() { *this = src; }
 
@@ -52,7 +52,7 @@ class String final : public StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[String::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Fw
 
diff --git a/Fw/Types/StringBase.cpp b/Fw/Types/StringBase.cpp
index 4cf1a95f8d..5fc9820488 100644
--- a/Fw/Types/StringBase.cpp
+++ b/Fw/Types/StringBase.cpp
@@ -114,7 +114,16 @@ void StringBase::appendBuff(const CHAR* buff, SizeType size) {
 }
 
 StringBase::SizeType StringBase::length() const {
-    return static_cast<SizeType>(StringUtils::string_length(this->toChar(), this->getCapacity()));
+    const SizeType length = static_cast<SizeType>(StringUtils::string_length(this->toChar(), this->getCapacity()));
+    FW_ASSERT(length <= this->maxLength(), static_cast<FwAssertArgType>(length),
+              static_cast<FwAssertArgType>(this->maxLength()));
+    return length;
+}
+
+StringBase::SizeType StringBase::maxLength() const {
+    const SizeType capacity = this->getCapacity();
+    FW_ASSERT(capacity > 0, static_cast<FwAssertArgType>(capacity));
+    return capacity - 1;
 }
 
 StringBase::SizeType StringBase::serializedSize() const {
@@ -130,16 +139,34 @@ SerializeStatus StringBase::serialize(SerializeBufferBase& buffer) const {
 }
 
 SerializeStatus StringBase::serialize(SerializeBufferBase& buffer, SizeType maxLength) const {
-    SizeType len = FW_MIN(maxLength, this->length());
-    return buffer.serialize(reinterpret_cast<const U8*>(this->toChar()), len);
+    const FwSizeType len = FW_MIN(maxLength, this->length());
+    // Serialize length and then bytes
+    return buffer.serialize(reinterpret_cast<const U8*>(this->toChar()), len, Serialization::INCLUDE_LENGTH);
 }
 
 SerializeStatus StringBase::deserialize(SerializeBufferBase& buffer) {
-    SizeType maxSize = this->getCapacity() - 1;
+    // Get the max size of the deserialized string
+    const SizeType maxSize = this->maxLength();
+    // Initial estimate of actual size is max size
+    // This estimate is refined when calling the deserialize function below
+    SizeType actualSize = maxSize;
+    // Public interface returns const char*, but implementation needs char*
+    // So use const_cast
     CHAR* raw = const_cast<CHAR*>(this->toChar());
-    SerializeStatus stat = buffer.deserialize(reinterpret_cast<U8*>(raw), maxSize);
-    // Null terminate deserialized string
-    raw[maxSize] = 0;
+    // Deserialize length
+    // Fail if length exceeds max size (the initial value of actualSize)
+    // Otherwise deserialize length bytes and set actualSize to length
+    SerializeStatus stat = buffer.deserialize(reinterpret_cast<U8*>(raw), actualSize, Serialization::INCLUDE_LENGTH);
+    if (stat == FW_SERIALIZE_OK) {
+        // Deserialization succeeded: null-terminate string at actual size
+        FW_ASSERT(actualSize <= maxSize, static_cast<FwAssertArgType>(actualSize),
+                  static_cast<FwAssertArgType>(maxSize));
+        raw[actualSize] = 0;
+    } else {
+        // Deserialization failed: leave string unmodified, but ensure that it
+        // is null-terminated
+        raw[maxSize] = 0;
+    }
     return stat;
 }
 }  // namespace Fw
diff --git a/Fw/Types/StringBase.hpp b/Fw/Types/StringBase.hpp
index 4e07bc33e8..d8cbe266ea 100644
--- a/Fw/Types/StringBase.hpp
+++ b/Fw/Types/StringBase.hpp
@@ -26,9 +26,31 @@ class StringBase : public Serializable {
     virtual const CHAR* toChar() const = 0;    //<! Convert to a C-style char*
     virtual SizeType getCapacity() const = 0;  //!< return size of buffer
     SizeType length() const;                   //!< Get length of string
-    SizeType serializedSize() const;           //!< Get length of string plus size of stored size
-    SizeType serializedTruncatedSize(
-        FwSizeType maxLength) const;  //!< Get truncated length of string plus size of stored size
+
+    //! Get the maximum length of a string that the buffer can hold
+    SizeType maxLength() const;
+    //! Get the static serialized size of a string
+    //! This is the max length of the string plus the size of the stored size
+    static constexpr SizeType STATIC_SERIALIZED_SIZE(SizeType maxLength  //!< The maximum string length
+    ) {
+        return sizeof(FwSizeStoreType) + maxLength;
+    }
+
+    //! Get the size of a null-terminated string buffer
+    static constexpr SizeType BUFFER_SIZE(SizeType maxLength  //!< The maximum string length
+    ) {
+        // Reserve one byte for each character plus one for the null terminator
+        return maxLength + 1;
+    }
+
+    //! Get the dynamic serialized size of a string
+    //! This is the length of the string plus the size of the stored size
+    SizeType serializedSize() const;
+
+    //! Get the serialized truncated size of a string
+    //! This is the minimum of the dynamic serialized size and the max length
+    SizeType serializedTruncatedSize(FwSizeType maxLength  //!< The max string length
+    ) const;
 
     const CHAR* operator+=(const CHAR* src);              //!< Concatenate a CHAR*
     const StringBase& operator+=(const StringBase& src);  //!< Concatenate a StringBase
@@ -60,9 +82,7 @@ class StringBase : public Serializable {
     void appendBuff(const CHAR* buff, SizeType size);
 
   private:
-    // A no-implementation copy constructor here will prevent the default copy constructor from being called
-    // accidentally, and without an implementation it will create an error for the developer instead.
-    StringBase(const StringBase& src);  //!< constructor with buffer as source
+    StringBase(const StringBase& src) = delete;  //!< constructor with buffer as source
 };
 
 }  // namespace Fw
diff --git a/Os/Pthreads/docs/sdd.md b/Os/Pthreads/docs/sdd.md
index f816468e08..2321cb3dc4 100644
--- a/Os/Pthreads/docs/sdd.md
+++ b/Os/Pthreads/docs/sdd.md
@@ -29,7 +29,7 @@ implemented using a stable maximum binary heap with *O(log(n))* enqueue and dequ
 has the property that items pulled off the queue are in order of decreasing priority. Items of equal priority are pulled off 
 in FIFO order.
 
-NOTE: [POSIX queues](https://elixir.bootlin.com/linux/latest/source/ipc/mqueue.c) use a dynamically sized [red-black tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) for the message queue data structure. This data structure also has an *O(log(n))* enqueue and dequeue time.
+NOTE: POSIX queues use a dynamically sized [red-black tree](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) for the message queue data structure. This data structure also has an *O(log(n))* enqueue and dequeue time.
 
 ## 2 Requirements
 
diff --git a/Os/QueueString.hpp b/Os/QueueString.hpp
index d7fda579f2..e7f6f9a056 100644
--- a/Os/QueueString.hpp
+++ b/Os/QueueString.hpp
@@ -15,15 +15,15 @@ namespace Os {
 
 class QueueString final : public Fw::StringBase {
   public:
-    enum { STRING_SIZE = FW_QUEUE_NAME_MAX_SIZE, SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType) };
+    enum { STRING_SIZE = FW_QUEUE_NAME_MAX_SIZE, SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE) };
 
     QueueString() : StringBase() { *this = ""; }
 
-    QueueString(const QueueString& src) : StringBase() { *this = src; }
+    explicit QueueString(const QueueString& src) : StringBase() { *this = src; }
 
-    QueueString(const StringBase& src) : StringBase() { *this = src; }
+    explicit QueueString(const StringBase& src) : StringBase() { *this = src; }
 
-    QueueString(const char* src) : StringBase() { *this = src; }
+    explicit QueueString(const char* src) : StringBase() { *this = src; }
 
     ~QueueString() {}
 
@@ -47,7 +47,7 @@ class QueueString final : public Fw::StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[QueueString::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Os
 
diff --git a/Os/TaskString.hpp b/Os/TaskString.hpp
index e22db533a0..7ebc5276e0 100644
--- a/Os/TaskString.hpp
+++ b/Os/TaskString.hpp
@@ -15,15 +15,15 @@ namespace Os {
 
 class TaskString final : public Fw::StringBase {
   public:
-    enum { STRING_SIZE = FW_TASK_NAME_MAX_SIZE, SERIALIZED_SIZE = STRING_SIZE + sizeof(FwSizeStoreType) };
+    enum { STRING_SIZE = FW_TASK_NAME_MAX_SIZE, SERIALIZED_SIZE = STATIC_SERIALIZED_SIZE(STRING_SIZE) };
 
     TaskString() : StringBase() { *this = ""; }
 
-    TaskString(const TaskString& src) : StringBase() { *this = src; }
+    explicit TaskString(const TaskString& src) : StringBase() { *this = src; }
 
-    TaskString(const StringBase& src) : StringBase() { *this = src; }
+    explicit TaskString(const StringBase& src) : StringBase() { *this = src; }
 
-    TaskString(const char* src) : StringBase() { *this = src; }
+    explicit TaskString(const char* src) : StringBase() { *this = src; }
 
     ~TaskString() {}
 
@@ -47,7 +47,7 @@ class TaskString final : public Fw::StringBase {
     StringBase::SizeType getCapacity() const { return sizeof this->m_buf; }
 
   private:
-    char m_buf[TaskString::STRING_SIZE];
+    char m_buf[BUFFER_SIZE(STRING_SIZE)];
 };
 }  // namespace Os
 
diff --git a/Ref/SignalGen/SignalGen.hpp b/Ref/SignalGen/SignalGen.hpp
index 98daceec7a..7d716646fc 100644
--- a/Ref/SignalGen/SignalGen.hpp
+++ b/Ref/SignalGen/SignalGen.hpp
@@ -40,20 +40,16 @@ namespace Ref {
             F32 Amplitude,
             F32 Phase,
             Ref::SignalType SigType
-        );
+        ) final;
 
         void SignalGen_Toggle_cmdHandler(
             FwOpcodeType opCode, /*!< The opcode*/
             U32 cmdSeq /*!< The command sequence number*/
-        );
+        ) final;
         void SignalGen_Skip_cmdHandler(
             FwOpcodeType opCode, /*!< The opcode*/
             U32 cmdSeq /*!< The command sequence number*/
-        );
-        void SignalGen_GenerateArray_cmdHandler(
-            FwOpcodeType opCode, /*!< The opcode*/
-            U32 cmdSeq /*!< The command sequence number*/
-        );
+        ) final;
 
         //! Handler implementation for command SignalGen_Dp
         //!
@@ -62,7 +58,7 @@ namespace Ref {
             FwOpcodeType opCode, //!< The opcode
             U32 cmdSeq, //!< The command sequence number
             U32 records
-        ) override;
+        ) final;
 
         // ----------------------------------------------------------------------
         // Handler implementations for data products
@@ -72,7 +68,7 @@ namespace Ref {
         void dpRecv_DataContainer_handler(
             DpContainer& container, //!< The container
             Fw::Success::T status //!< The container status
-        ) override;
+        ) final;
 
 
     public:
diff --git a/Svc/BufferLogger/BufferLoggerFile.cpp b/Svc/BufferLogger/BufferLoggerFile.cpp
index 84b5698ab8..6d3268c735 100644
--- a/Svc/BufferLogger/BufferLoggerFile.cpp
+++ b/Svc/BufferLogger/BufferLoggerFile.cpp
@@ -225,7 +225,7 @@ namespace Svc {
     const Os::ValidateFile::Status status =
       validatedFile.createHashFile();
     if (status !=  Os::ValidateFile::VALIDATION_OK) {
-      const Fw::String &hashFileName = validatedFile.getHashFileName();
+      const Fw::StringBase &hashFileName = validatedFile.getHashFileName();
       Fw::LogStringArg logStringArg(hashFileName.toChar());
       this->m_bufferLogger.log_WARNING_HI_BL_LogFileValidationError(
           logStringArg,
diff --git a/Svc/CmdSequencer/CmdSequencerImpl.cpp b/Svc/CmdSequencer/CmdSequencerImpl.cpp
index cb412cf44d..7e1c84d25b 100644
--- a/Svc/CmdSequencer/CmdSequencerImpl.cpp
+++ b/Svc/CmdSequencer/CmdSequencerImpl.cpp
@@ -70,7 +70,7 @@ namespace Svc {
     }
 
     void CmdSequencerComponentImpl ::
-      loadSequence(const Fw::String& fileName)
+      loadSequence(const Fw::StringBase& fileName)
     {
       FW_ASSERT(this->m_runMode == STOPPED, this->m_runMode);
       if (not this->loadFile(fileName)) {
@@ -245,7 +245,7 @@ namespace Svc {
     // ----------------------------------------------------------------------
 
     bool CmdSequencerComponentImpl ::
-      loadFile(const Fw::CmdStringArg& fileName)
+      loadFile(const Fw::StringBase& fileName)
     {
       const bool status = this->m_sequence->loadFile(fileName);
       if (status) {
diff --git a/Svc/CmdSequencer/CmdSequencerImpl.hpp b/Svc/CmdSequencer/CmdSequencerImpl.hpp
index f9739a6c9e..6e595000b4 100644
--- a/Svc/CmdSequencer/CmdSequencerImpl.hpp
+++ b/Svc/CmdSequencer/CmdSequencerImpl.hpp
@@ -225,7 +225,7 @@ namespace Svc {
           );
 
           //! Set the file name. Also sets the log file name.
-          void setFileName(const Fw::CmdStringArg& fileName);
+          void setFileName(const Fw::StringBase& fileName);
 
           //! Get the file name
           //! \return The file name
@@ -241,7 +241,7 @@ namespace Svc {
           //! Load a sequence file
           //! \return Success or failure
           virtual bool loadFile(
-              const Fw::CmdStringArg& fileName //!< The file name
+              const Fw::StringBase& fileName //!< The file name
           ) = 0;
 
           //! Query whether the sequence has any more records
@@ -341,7 +341,7 @@ namespace Svc {
           //! Load a sequence file
           //! \return Success or failure
           bool loadFile(
-              const Fw::CmdStringArg& fileName //!< The file name
+              const Fw::StringBase& fileName //!< The file name
           );
 
           //! Query whether the sequence has any more records
@@ -548,7 +548,7 @@ namespace Svc {
       //! (Optional) Load a sequence to run later.
       //! When you call this function, the event ports must be connected.
       void loadSequence(
-          const Fw::String& fileName //!< The file name
+          const Fw::StringBase& fileName //!< The file name
       );
 
       //! Return allocated buffer. Call during shutdown.
@@ -673,7 +673,7 @@ namespace Svc {
       //! Load a sequence file
       //! \return Success or failure
       bool loadFile(
-          const Fw::CmdStringArg& fileName //!< The file name
+          const Fw::StringBase& fileName //!< The file name
       );
 
       //! Perform a Cancel command
diff --git a/Svc/CmdSequencer/FPrimeSequence.cpp b/Svc/CmdSequencer/FPrimeSequence.cpp
index a94624f8f3..f51343709a 100644
--- a/Svc/CmdSequencer/FPrimeSequence.cpp
+++ b/Svc/CmdSequencer/FPrimeSequence.cpp
@@ -67,7 +67,7 @@ namespace Svc {
   }
 
   bool CmdSequencerComponentImpl::FPrimeSequence ::
-    loadFile(const Fw::CmdStringArg& fileName)
+    loadFile(const Fw::StringBase& fileName)
   {
 
     // make sure there is a buffer allocated
diff --git a/Svc/CmdSequencer/Sequence.cpp b/Svc/CmdSequencer/Sequence.cpp
index 4f905d5567..235de84c13 100644
--- a/Svc/CmdSequencer/Sequence.cpp
+++ b/Svc/CmdSequencer/Sequence.cpp
@@ -108,7 +108,7 @@ namespace Svc {
     }
 
     void CmdSequencerComponentImpl::Sequence ::
-      setFileName(const Fw::CmdStringArg& fileName)
+      setFileName(const Fw::StringBase& fileName)
     {
         this->m_fileName = fileName;
         this->m_logFileName = fileName;
diff --git a/Svc/CmdSequencer/formats/AMPCSSequence.cpp b/Svc/CmdSequencer/formats/AMPCSSequence.cpp
index 051f90b853..a8347719ea 100644
--- a/Svc/CmdSequencer/formats/AMPCSSequence.cpp
+++ b/Svc/CmdSequencer/formats/AMPCSSequence.cpp
@@ -27,12 +27,12 @@ namespace Svc {
   }
 
   bool AMPCSSequence ::
-    loadFile(const Fw::CmdStringArg& fileName)
+    loadFile(const Fw::StringBase& fileName)
   {
     // Make sure there is a buffer allocated
     FW_ASSERT(this->m_buffer.getBuffAddr());
 
-    Fw::CmdStringArg crcFileName = fileName;
+    Fw::CmdStringArg crcFileName(fileName);
     crcFileName += ".CRC32";
 
     this->m_header.m_timeBase = TB_DONT_CARE;
@@ -77,7 +77,7 @@ namespace Svc {
   }
 
   bool AMPCSSequence ::
-    getFileSize(const Fw::CmdStringArg& seqFileName)
+    getFileSize(const Fw::StringBase& seqFileName)
   {
     bool status = true;
     FwSignedSizeType fileSize;
@@ -101,7 +101,7 @@ namespace Svc {
   }
 
   bool AMPCSSequence ::
-    readSequenceFile(const Fw::CmdStringArg& seqFileName)
+    readSequenceFile(const Fw::StringBase& seqFileName)
   {
 
     bool result;
diff --git a/Svc/CmdSequencer/formats/AMPCSSequence.hpp b/Svc/CmdSequencer/formats/AMPCSSequence.hpp
index 2f719a9397..c043568ca4 100644
--- a/Svc/CmdSequencer/formats/AMPCSSequence.hpp
+++ b/Svc/CmdSequencer/formats/AMPCSSequence.hpp
@@ -100,7 +100,7 @@ namespace Svc {
       //! Load a sequence file
       //! \return Success or failure
       bool loadFile(
-          const Fw::CmdStringArg& fileName //!< The file name
+          const Fw::StringBase& fileName //!< The file name
       );
 
       //! Query whether the sequence has any more records
@@ -141,13 +141,13 @@ namespace Svc {
       //! Get the aggregate size of the command records
       //! \return Success or failure
       bool getFileSize(
-          const Fw::CmdStringArg& seqFileName //!< The sequence file name
+          const Fw::StringBase& seqFileName //!< The sequence file name
       );
 
       //! Read a sequence file
       //! \return Success or failure
       bool readSequenceFile(
-          const Fw::CmdStringArg& seqFileName //!< The sequence file name
+          const Fw::StringBase& seqFileName //!< The sequence file name
       );
 
       //! Read an open sequence file
diff --git a/Svc/DpWriter/DpWriter.cpp b/Svc/DpWriter/DpWriter.cpp
index dd8765d1db..1eda1283d2 100644
--- a/Svc/DpWriter/DpWriter.cpp
+++ b/Svc/DpWriter/DpWriter.cpp
@@ -183,7 +183,7 @@ Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container,
     Os::File file;
     Os::File::Status fileStatus = file.open(fileName.toChar(), Os::File::OPEN_CREATE);
     if (fileStatus != Os::File::OP_OK) {
-        this->log_WARNING_HI_FileOpenError(static_cast<U32>(fileStatus), fileName.toChar());
+        this->log_WARNING_HI_FileOpenError(static_cast<U32>(fileStatus), fileName);
         status = Fw::Success::FAILURE;
     }
     // Write the file
@@ -202,11 +202,11 @@ Fw::Success::T DpWriter::writeFile(const Fw::DpContainer& container,
             // is the expected number, then record the success
             this->log_ACTIVITY_LO_FileWritten(
                 static_cast<U32>(writeSize),
-                fileName.toChar());
+                fileName);
         } else {
             // Otherwise record the failure
             this->log_WARNING_HI_FileWriteError(static_cast<U32>(fileStatus), static_cast<U32>(writeSize),
-                                                static_cast<U32>(fileSize), fileName.toChar());
+                                                static_cast<U32>(fileSize), fileName);
             status = Fw::Success::FAILURE;
         }
     }
diff --git a/requirements.txt b/requirements.txt
index 5bff09c472..c04fe3357b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,18 +18,18 @@ fprime-fpl-convert-xml==1.0.3
 fprime-fpl-extract-xml==1.0.3
 fprime-fpl-layout==1.0.3
 fprime-fpl-write-pic==1.0.3
-fprime-fpp-check==2.1.0a9
-fprime-fpp-depend==2.1.0a9
-fprime-fpp-filenames==2.1.0a9
-fprime-fpp-format==2.1.0a9
-fprime-fpp-from-xml==2.1.0a9
-fprime-fpp-locate-defs==2.1.0a9
-fprime-fpp-locate-uses==2.1.0a9
-fprime-fpp-syntax==2.1.0a9
-fprime-fpp-to-cpp==2.1.0a9
-fprime-fpp-to-dict==2.1.0a9
-fprime-fpp-to-json==2.1.0a9
-fprime-fpp-to-xml==2.1.0a9
+fprime-fpp-check==2.1.0a10
+fprime-fpp-depend==2.1.0a10
+fprime-fpp-filenames==2.1.0a10
+fprime-fpp-format==2.1.0a10
+fprime-fpp-from-xml==2.1.0a10
+fprime-fpp-locate-defs==2.1.0a10
+fprime-fpp-locate-uses==2.1.0a10
+fprime-fpp-syntax==2.1.0a10
+fprime-fpp-to-cpp==2.1.0a10
+fprime-fpp-to-dict==2.1.0a10
+fprime-fpp-to-json==2.1.0a10
+fprime-fpp-to-xml==2.1.0a10
 fprime-gds==3.4.3
 fprime-tools==3.4.4
 fprime-visual==1.0.2


Test patch:
diff --git a/FppTest/dp/test/ut/Tester.cpp b/FppTest/dp/test/ut/Tester.cpp
index a37f75a568..201613a6d5 100644
--- a/FppTest/dp/test/ut/Tester.cpp
+++ b/FppTest/dp/test/ut/Tester.cpp
@@ -331,8 +331,7 @@ Fw::Time Tester::randomizeTestTime() {
 }
 
 void Tester::generateRandomString(Fw::StringBase& str) {
-    // Reserve enough space for max length plus null terminator
-    char buffer[MAX_STRING_LENGTH + 1];
+    char buffer[Fw::StringBase::BUFFER_SIZE(MAX_STRING_LENGTH)];
     // Pick a random string length
     const FwSizeType length = STest::Pick::lowerUpper(0, MAX_STRING_LENGTH);
     // Fill buffer with a random null-terminated string with that length
diff --git a/Fw/Logger/test/ut/LoggerMain.cpp b/Fw/Logger/test/ut/LoggerMain.cpp
index 14d52daaf9..8ef9dc8d02 100644
--- a/Fw/Logger/test/ut/LoggerMain.cpp
+++ b/Fw/Logger/test/ut/LoggerMain.cpp
@@ -25,9 +25,9 @@ TEST(LoggerTests, RandomLoggerTests) {
     MockLogging::FakeLogger logger;
 
     // Create rules, and assign them into the array
-    LoggerRules::Register reg("Register");
-    LoggerRules::LogGood log("Log Successfully");
-    LoggerRules::LogBad nolog("Log unsuccessfully");
+    LoggerRules::Register reg(Fw::String("Register"));
+    LoggerRules::LogGood log(Fw::String("Log Successfully"));
+    LoggerRules::LogBad nolog(Fw::String("Log unsuccessfully"));
 
     // Setup a list of rules to choose from
     STest::Rule<MockLogging::FakeLogger>* rules[] = {
@@ -55,7 +55,7 @@ TEST(LoggerTests, BasicGoodLogger) {
     Fw::Logger::registerLogger(&logger);
     logger.s_current = &logger;
     // Basic logging
-    LoggerRules::LogGood log("Log Successfully");
+    LoggerRules::LogGood log(Fw::String("Log Successfully"));
     log.apply(logger);
 }
 /**
@@ -66,7 +66,7 @@ TEST(LoggerTests, BasicBadLogger) {
     MockLogging::FakeLogger logger;
     Fw::Logger::registerLogger(nullptr);
     logger.s_current = nullptr;
-    LoggerRules::LogBad log("Log Discarded");
+    LoggerRules::LogBad log(Fw::String("Log Discarded"));
     log.apply(logger);
 }
 
@@ -76,7 +76,7 @@ TEST(LoggerTests, BasicBadLogger) {
 TEST(LoggerTests, BasicRegLogger) {
     // Basic discard logging
     MockLogging::FakeLogger logger;
-    LoggerRules::Register reg("Register");
+    LoggerRules::Register reg(Fw::String("Register"));
     reg.apply(logger);
     reg.apply(logger);
     reg.apply(logger);
diff --git a/Fw/Types/test/ut/TypesTest.cpp b/Fw/Types/test/ut/TypesTest.cpp
index 20142cf758..9bd5a05fe9 100644
--- a/Fw/Types/test/ut/TypesTest.cpp
+++ b/Fw/Types/test/ut/TypesTest.cpp
@@ -1127,7 +1127,7 @@ TEST(TypesTest, StringTest) {
     str2 = "doodie";
     ASSERT_NE(str, str2);
 
-    Fw::String str3 = str;
+    Fw::String str3(str);
     str3 += str2;
     ASSERT_EQ(str3, "foodoodie");
 
@@ -1136,7 +1136,7 @@ TEST(TypesTest, StringTest) {
 
     Fw::String copyStr("ASTRING");
     ASSERT_EQ(copyStr, "ASTRING");
-    Fw::String copyStr2 = "ASTRING";
+    Fw::String copyStr2("ASTRING");
     ASSERT_EQ(copyStr2, "ASTRING");
     Fw::String copyStr3(copyStr2);
     ASSERT_EQ(copyStr3, "ASTRING");
@@ -1168,7 +1168,7 @@ TEST(TypesTest, ObjectNameTest) {
     str2 = "_bar";
     ASSERT_NE(str, str2);
 
-    Fw::ObjectName str3 = str;
+    Fw::ObjectName str3(str);
     str3 += str2;
     ASSERT_EQ(str3, "foo_bar");
 
diff --git a/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp b/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp
index 9c6306f410..800ed84be7 100644
--- a/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp
+++ b/Svc/BufferLogger/test/ut/BufferLoggerTester.cpp
@@ -251,7 +251,7 @@ namespace Svc {
     checkHashFileExists(const Fw::StringBase& fileName)
   {
     Os::ValidatedFile validatedFile(fileName.toChar());
-    const Fw::String& hashFileName = validatedFile.getHashFileName();
+    const Fw::StringBase& hashFileName = validatedFile.getHashFileName();
     this->checkFileExists(hashFileName);
   }
 
diff --git a/Svc/BufferLogger/test/ut/Errors.cpp b/Svc/BufferLogger/test/ut/Errors.cpp
index b3edec5586..5c56103742 100644
--- a/Svc/BufferLogger/test/ut/Errors.cpp
+++ b/Svc/BufferLogger/test/ut/Errors.cpp
@@ -187,7 +187,7 @@ namespace Svc {
           fileName.toChar()
       );
       Os::ValidatedFile validatedFile(fileName.toChar());
-      const Fw::String& hashFileName = validatedFile.getHashFileName();
+      const Fw::StringBase& hashFileName = validatedFile.getHashFileName();
       ASSERT_EVENTS_BL_LogFileValidationError(
           0,
           hashFileName.toChar(),
diff --git a/Svc/BufferLogger/test/ut/Logging.cpp b/Svc/BufferLogger/test/ut/Logging.cpp
index e86b3971e7..2ef7775568 100644
--- a/Svc/BufferLogger/test/ut/Logging.cpp
+++ b/Svc/BufferLogger/test/ut/Logging.cpp
@@ -96,7 +96,7 @@ namespace Svc {
         //! Run a test
         void test(
             const U32 numFiles, //!< The number of files to create
-            const char *const baseName //!< The baseName to use
+            const Fw::CmdStringArg& baseName //!< The baseName to use
         ) {
           this->sendCmd_BL_OpenFile(0, 0, baseName);
           this->dispatchOne();
@@ -105,7 +105,7 @@ namespace Svc {
           currentFileName.format(
               "%s%s%s",
               this->component.m_file.m_prefix.toChar(),
-              baseName,
+              baseName.toChar(),
               this->component.m_file.m_suffix.toChar()
           );
           this->sendBuffers(1);
@@ -123,7 +123,7 @@ namespace Svc {
             currentFileName.format(
                 "%s%s%d%s",
                 this->component.m_file.m_prefix.toChar(),
-                baseName,
+                baseName.toChar(),
                 i,
                 this->component.m_file.m_suffix.toChar()
             );
@@ -147,7 +147,7 @@ namespace Svc {
                 fileName.format(
                     "%s%s%s",
                     this->component.m_file.m_prefix.toChar(),
-                    baseName,
+                    baseName.toChar(),
                     this->component.m_file.m_suffix.toChar()
                 );
             }
@@ -155,7 +155,7 @@ namespace Svc {
                 fileName.format(
                     "%s%s%d%s",
                     this->component.m_file.m_prefix.toChar(),
-                    baseName,
+                    baseName.toChar(),
                     i,
                     this->component.m_file.m_suffix.toChar()
                 );
@@ -190,7 +190,7 @@ namespace Svc {
       ComIn()
     {
       ComInTester tester;
-      tester.test(3, "ComIn");
+      tester.test(3, Fw::CmdStringArg("ComIn"));
     }
 
     class BufferSendInTester :
@@ -207,7 +207,7 @@ namespace Svc {
       BufferSendIn()
     {
       BufferSendInTester tester;
-      tester.test(3, "BufferSendIn");
+      tester.test(3, Fw::CmdStringArg("BufferSendIn"));
     }
 
     class OnOffTester :
diff --git a/Svc/CmdSequencer/test/ut/AMPCS.cpp b/Svc/CmdSequencer/test/ut/AMPCS.cpp
index 5cb305ff7f..69c2e89b05 100644
--- a/Svc/CmdSequencer/test/ut/AMPCS.cpp
+++ b/Svc/CmdSequencer/test/ut/AMPCS.cpp
@@ -36,10 +36,9 @@ namespace Svc {
     {
       // Write the file
       SequenceFiles::MissingCRCFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert no response on seqDone
       ASSERT_from_seqDone_SIZE(0);
@@ -52,7 +51,7 @@ namespace Svc {
           Fw::CmdResponse::EXECUTION_ERROR
       );
       // Assert events
-      Fw::String crcFileName(fileName);
+      Fw::String crcFileName(file.getName());
       crcFileName += ".CRC32";
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_FileNotFound(0, crcFileName.toChar());
@@ -66,11 +65,10 @@ namespace Svc {
     {
       // Remove the file
       SequenceFiles::MissingFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       file.remove();
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -84,7 +82,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_FileInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           CmdSequencer_FileReadStage::READ_HEADER_SIZE,
           Os::FileSystem::INVALID_PATH
       );
diff --git a/Svc/CmdSequencer/test/ut/CmdSequencerTester.cpp b/Svc/CmdSequencer/test/ut/CmdSequencerTester.cpp
index e6ef0a5492..cccea48610 100644
--- a/Svc/CmdSequencer/test/ut/CmdSequencerTester.cpp
+++ b/Svc/CmdSequencer/test/ut/CmdSequencerTester.cpp
@@ -204,7 +204,6 @@ namespace Svc {
     Fw::Time testTime(TB_WORKSTATION_TIME, 1, 1);
     this->setTestTime(testTime);
     // Write the file
-    const char *const fileName = file.getName().toChar();
     file.write();
     // Get error info
     SequenceFiles::File::ErrorInfo errorInfo;
@@ -216,7 +215,7 @@ namespace Svc {
     {
       this->interceptor.fileStatus = Os::File::Status::DOESNT_EXIST;
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert events
       ASSERT_EVENTS_SIZE(1);
@@ -228,7 +227,7 @@ namespace Svc {
       this->interceptor.fileStatus = Os::File::NO_PERMISSION;
       // Validate the file
       const U32 validateCmdSeq = 14;
-      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, fileName);
+      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -254,7 +253,6 @@ namespace Svc {
     Fw::Time testTime(TB_WORKSTATION_TIME, 1, 1);
     this->setTestTime(testTime);
     // Write the file
-    const char *const fileName = file.getName().toChar();
     file.write();
     // Get error info
     SequenceFiles::File::ErrorInfo errorInfo;
@@ -271,7 +269,7 @@ namespace Svc {
       //TODO: fix me Os::setLastError(Os::File::NO_SPACE);
       // Validate file
       const U32 validateCmdSeq = 14;
-      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, fileName);
+      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -301,7 +299,6 @@ namespace Svc {
     Fw::Time testTime(TB_WORKSTATION_TIME, 1, 1);
     this->setTestTime(testTime);
     // Write the file
-    const char *const fileName = file.getName().toChar();
     file.write();
     // Get error info
     SequenceFiles::File::ErrorInfo errorInfo;
@@ -318,7 +315,7 @@ namespace Svc {
 
       // Validate file
       const U32 validateCmdSeq = 14;
-      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, fileName);
+      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -347,7 +344,7 @@ namespace Svc {
       this->interceptor.size = 2;
       // Validate file
       const U32 validateCmdSeq = 14;
-      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, fileName);
+      this->sendCmd_CS_VALIDATE(0, validateCmdSeq, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -604,7 +601,7 @@ namespace Svc {
     validateFile(const U32 cmdSeq, const char* const fileName)
   {
     // Validate the file
-    this->sendCmd_CS_VALIDATE(0, cmdSeq, fileName);
+    this->sendCmd_CS_VALIDATE(0, cmdSeq, Fw::CmdStringArg(fileName));
     this->clearAndDispatch();
     // Assert command response
     ASSERT_CMD_RESPONSE_SIZE(1);
@@ -626,7 +623,7 @@ namespace Svc {
     // Invoke the port
     Fw::String fArg(fileName);
     this->clearHistory();
-    this->component.loadSequence(fileName);
+    this->component.loadSequence(fArg);
     // Assert events
     ASSERT_EVENTS_SIZE(1);
     ASSERT_EVENTS_CS_SequenceLoaded(0, fileName);
@@ -636,7 +633,7 @@ namespace Svc {
     runSequence(const U32 cmdSeq, const char* const fileName)
   {
     // Send run command
-    this->sendCmd_CS_RUN(0, cmdSeq, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+    this->sendCmd_CS_RUN(0, cmdSeq, Fw::CmdStringArg(fileName), Svc::CmdSequencer_BlockState::NO_BLOCK);
     this->clearAndDispatch();
     // Assert command response
     ASSERT_CMD_RESPONSE_SIZE(1);
@@ -686,7 +683,7 @@ namespace Svc {
     startNewSequence(const char *const fileName)
   {
     // Start the sequence
-    this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+    this->sendCmd_CS_RUN(0, 0, Fw::CmdStringArg(fileName), Svc::CmdSequencer_BlockState::NO_BLOCK);
     this->clearAndDispatch();
     // Assert command response
     ASSERT_CMD_RESPONSE_SIZE(1);
@@ -699,7 +696,7 @@ namespace Svc {
     ASSERT_EVENTS_SIZE(1);
     ASSERT_EVENTS_CS_InvalidMode_SIZE(1);
     // Validate the file
-    this->sendCmd_CS_VALIDATE(0, 0, fileName);
+    this->sendCmd_CS_VALIDATE(0, 0, Fw::CmdStringArg(fileName));
     this->clearAndDispatch();
     // Assert command response
     ASSERT_CMD_RESPONSE_SIZE(1);
diff --git a/Svc/CmdSequencer/test/ut/InvalidFiles.cpp b/Svc/CmdSequencer/test/ut/InvalidFiles.cpp
index 3c12924c4f..1ce74d6535 100644
--- a/Svc/CmdSequencer/test/ut/InvalidFiles.cpp
+++ b/Svc/CmdSequencer/test/ut/InvalidFiles.cpp
@@ -43,10 +43,9 @@ namespace Svc {
       this->setTestTime(testTime);
       // Write the file
       SequenceFiles::BadCRCFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -62,7 +61,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_FileCrcFailure(
           0,
-          fileName,
+          file.getName().toChar(),
           crc.m_stored,
           crc.m_computed
       );
@@ -80,10 +79,9 @@ namespace Svc {
       // Write the file
       NATIVE_INT_TYPE numRecords = 1;
       SequenceFiles::BadDescriptorFile file(numRecords, this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -97,12 +95,12 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_FORMAT_ERROR
       );
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -116,7 +114,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_FORMAT_ERROR
       );
@@ -131,10 +129,9 @@ namespace Svc {
       // Write the file
       const NATIVE_INT_TYPE numRecords = 5;
       SequenceFiles::BadTimeBaseFile file(numRecords, this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -149,7 +146,7 @@ namespace Svc {
       ASSERT_EVENTS_CS_TimeBaseMismatch_SIZE(1);
       ASSERT_EVENTS_CS_TimeBaseMismatch(
           0,
-          fileName,
+          file.getName().toChar(),
           TB_WORKSTATION_TIME,
           TB_PROC_TIME
       );
@@ -164,10 +161,9 @@ namespace Svc {
       // Write the file
       const U32 numRecords = 5;
       SequenceFiles::BadTimeContextFile file(numRecords, this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -180,7 +176,7 @@ namespace Svc {
       // Assert events
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_TimeContextMismatch_SIZE(1);
-      ASSERT_EVENTS_CS_TimeContextMismatch(0, fileName, 0, 1);
+      ASSERT_EVENTS_CS_TimeContextMismatch(0, file.getName().toChar(), 0, 1);
     }
 
     void CmdSequencerTester ::
@@ -188,10 +184,9 @@ namespace Svc {
     {
       // Write the file
       SequenceFiles::EmptyFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -205,7 +200,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_FileInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           CmdSequencer_FileReadStage::READ_HEADER_SIZE,
           Os::FileSystem::OP_OK
       );
@@ -226,10 +221,9 @@ namespace Svc {
       // Write the file
       const U32 numRecords = 5;
       SequenceFiles::DataAfterRecordsFile file(numRecords, this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -242,7 +236,7 @@ namespace Svc {
       // Assert events
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_RecordMismatch_SIZE(1);
-      ASSERT_EVENTS_CS_RecordMismatch(0, fileName, 5, 8);
+      ASSERT_EVENTS_CS_RecordMismatch(0, file.getName().toChar(), 5, 8);
 
     }
 
@@ -251,13 +245,12 @@ namespace Svc {
     {
       // Write the file
       SequenceFiles::TooLargeFile file(BUFFER_SIZE, this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Set the time
       Fw::Time testTime(TB_WORKSTATION_TIME, 0, 0);
       this->setTestTime(testTime);
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -270,7 +263,7 @@ namespace Svc {
       // Assert events
       ASSERT_EVENTS_SIZE(1);
       const U32 dataSize = file.getDataSize();
-      ASSERT_EVENTS_CS_FileSizeError(0, fileName, dataSize);
+      ASSERT_EVENTS_CS_FileSizeError(0, file.getName().toChar(), dataSize);
       // Assert telemetry
       ASSERT_TLM_SIZE(1);
       ASSERT_TLM_CS_Errors(0, 1);
@@ -281,10 +274,9 @@ namespace Svc {
     {
       // Write the file
       SequenceFiles::MissingCRCFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert no response on seqDone
       ASSERT_from_seqDone_SIZE(0);
@@ -300,7 +292,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_FileInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           CmdSequencer_FileReadStage::READ_SEQ_CRC,
           sizeof(U8)
       );
@@ -308,7 +300,7 @@ namespace Svc {
       ASSERT_TLM_SIZE(1);
       ASSERT_TLM_CS_Errors(0, 1);
       // Validate file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert no response on seqDone
       ASSERT_from_seqDone_SIZE(0);
@@ -324,7 +316,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_FileInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           CmdSequencer_FileReadStage::READ_SEQ_CRC,
           sizeof(U8)
       );
@@ -332,7 +324,7 @@ namespace Svc {
       ASSERT_TLM_SIZE(1);
       ASSERT_TLM_CS_Errors(0, 2);
       // Run the sequence by port call
-      Fw::String fArg(fileName);
+      Fw::String fArg(file.getName());
       this->invoke_to_seqRunIn(0, fArg);
       this->clearAndDispatch();
       // Assert seqDone response
@@ -342,7 +334,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_FileInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           CmdSequencer_FileReadStage::READ_SEQ_CRC,
           sizeof(U8)
       );
@@ -356,10 +348,9 @@ namespace Svc {
     {
       // Remove the file
       SequenceFiles::MissingFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.remove();
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -371,7 +362,7 @@ namespace Svc {
       );
       // Assert events
       ASSERT_EVENTS_SIZE(1);
-      ASSERT_EVENTS_CS_FileNotFound(0, fileName);
+      ASSERT_EVENTS_CS_FileNotFound(0, file.getName().toChar());
       // Assert telemetry
       ASSERT_TLM_SIZE(1);
       ASSERT_TLM_CS_Errors(0, 1);
@@ -385,10 +376,9 @@ namespace Svc {
       this->setTestTime(testTime);
       // Write the file
       SequenceFiles::SizeFieldTooLargeFile file(BUFFER_SIZE, this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -402,12 +392,12 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_SIZE_MISMATCH
       );
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -421,7 +411,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_SIZE_MISMATCH
       );
@@ -435,10 +425,9 @@ namespace Svc {
       this->setTestTime(testTime);
       // Write the file
       SequenceFiles::SizeFieldTooSmallFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -453,12 +442,12 @@ namespace Svc {
       ASSERT_EVENTS_CS_RecordInvalid_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_SIZE_MISMATCH
       );
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -473,7 +462,7 @@ namespace Svc {
       ASSERT_EVENTS_CS_RecordInvalid_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_SIZE_MISMATCH
       );
@@ -487,10 +476,9 @@ namespace Svc {
       this->setTestTime(testTime);
       // Write the file
       SequenceFiles::USecFieldTooShortFile file(this->format);
-      const char *const fileName = file.getName().toChar();
       file.write();
       // Validate the file
-      this->sendCmd_CS_VALIDATE(0, 0, fileName);
+      this->sendCmd_CS_VALIDATE(0, 0, file.getName());
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -504,12 +492,12 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_SIZE_MISMATCH
       );
       // Run the sequence
-      this->sendCmd_CS_RUN(0, 0, fileName,Svc::CmdSequencer_BlockState::NO_BLOCK);
+      this->sendCmd_CS_RUN(0, 0, file.getName(), Svc::CmdSequencer_BlockState::NO_BLOCK);
       this->clearAndDispatch();
       // Assert command response
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -523,7 +511,7 @@ namespace Svc {
       ASSERT_EVENTS_SIZE(1);
       ASSERT_EVENTS_CS_RecordInvalid(
           0,
-          fileName,
+          file.getName().toChar(),
           0,
           Fw::FW_DESERIALIZE_SIZE_MISMATCH
       );
diff --git a/Svc/Health/test/ut/HealthTester.cpp b/Svc/Health/test/ut/HealthTester.cpp
index e35bbe5b4d..d1b856e314 100644
--- a/Svc/Health/test/ut/HealthTester.cpp
+++ b/Svc/Health/test/ut/HealthTester.cpp
@@ -437,7 +437,7 @@ namespace Svc {
           char name[80];
           snprintf(name, sizeof(name), "task%d",entry);
           Fw::CmdStringArg task(name);
-          this->sendCmd_HLTH_PING_ENABLE(0,10,name,Fw::Enabled::DISABLED);
+          this->sendCmd_HLTH_PING_ENABLE(0,10,task,Fw::Enabled::DISABLED);
           this->dispatchAll();
           ASSERT_CMD_RESPONSE_SIZE(1);
           ASSERT_CMD_RESPONSE(0,HealthComponentBase::OPCODE_HLTH_PING_ENABLE,10,Fw::CmdResponse::OK);
@@ -466,7 +466,7 @@ namespace Svc {
           this->clearEvents();
           this->clearHistory();
 
-          this->sendCmd_HLTH_PING_ENABLE(0,10,name,Fw::Enabled::ENABLED);
+          this->sendCmd_HLTH_PING_ENABLE(0,10,task,Fw::Enabled::ENABLED);
           this->dispatchAll();
           ASSERT_CMD_RESPONSE_SIZE(1);
           ASSERT_CMD_RESPONSE(0,HealthComponentBase::OPCODE_HLTH_PING_ENABLE,10,Fw::CmdResponse::OK);
@@ -542,8 +542,8 @@ namespace Svc {
 	  TEST_CASE(900.1.8,"Nominal Command");
 	  COMMENT("Process command during quiescent (no telemetry readout) period.");
 
-	  Fw::LogStringArg arg = "task0";
-	  Fw::CmdStringArg carg = arg;
+	  Fw::LogStringArg arg("task0");
+	  Fw::CmdStringArg carg(arg);
 
 	  ASSERT_EVENTS_SIZE(0);
 	  ASSERT_TLM_SIZE(0);
@@ -671,14 +671,14 @@ namespace Svc {
 
       //send command with bad value
       Fw::Enabled badValue = static_cast<Fw::Enabled::t>(Fw::Enabled::NUM_CONSTANTS);
-      sendCmd_HLTH_PING_ENABLE(0,0,"task0",badValue);
+      sendCmd_HLTH_PING_ENABLE(0,0,Fw::CmdStringArg("task0"),badValue);
       this->dispatchAll();
 
       ASSERT_CMD_RESPONSE_SIZE(1);
       ASSERT_CMD_RESPONSE(0,HealthComponentBase::OPCODE_HLTH_PING_ENABLE,0,Fw::CmdResponse::FORMAT_ERROR);
 
       //send command with bad ping entry
-      sendCmd_HLTH_PING_ENABLE(0,0,"notask",Fw::Enabled::ENABLED);
+      sendCmd_HLTH_PING_ENABLE(0,0,Fw::CmdStringArg("notask"),Fw::Enabled::ENABLED);
       this->dispatchAll();
 
       ASSERT_CMD_RESPONSE_SIZE(2);
@@ -690,7 +690,7 @@ namespace Svc {
       this->clearHistory();
 
       //send update timeout command with bad thresholds
-      sendCmd_HLTH_CHNG_PING(0, 0,"task0", 10, 9);
+      sendCmd_HLTH_CHNG_PING(0, 0,Fw::CmdStringArg("task0"), 10, 9);
       this->dispatchAll();
 
       ASSERT_CMD_RESPONSE_SIZE(1);
@@ -703,7 +703,7 @@ namespace Svc {
       this->clearHistory();
 
       //send update timeout command with ping entry
-      sendCmd_HLTH_CHNG_PING(0, 0, "sometask", 1, 2);
+      sendCmd_HLTH_CHNG_PING(0, 0, Fw::CmdStringArg("sometask"), 1, 2);
       this->dispatchAll();
 
       ASSERT_CMD_RESPONSE_SIZE(1);