C# FIT SDK WriteField method - potential bug

I am trying to write a parser using the C# Fit SDK to parse fit files into JSON and back to FIT preserving the message types that are unknown (i.e. not in the official SDK but present in the Fit file). This is done by using the original fit file as basis for the unknown fields. This means that I use the messages read from the original FIT file and rewrite them to the new one (without change). However, I came across and edge case where writing the Fit message to the file resulted in an infinit loop in the Mesg.cs WriteField method (specifically at the first while loop):

private static void WriteField(FieldBase field, byte size, BinaryWriter bw)
{
    byte baseType = (byte)(field.Type & Fit.BaseTypeNumMask);
    
    // The field could be blank, correctly formed or partially filled
    while (field.GetSize() < size)
    {
        if (baseType == Fit.String)
        {
            // Figure out how much we have to pad
            byte padAmount = (byte)(size - field.GetSize());
            //Has to be a string.
            try
            {
                // Get the Last Value of the field
                byte[] value = (byte[])field.GetValue(field.GetNumValues() - 1);
                List<byte> temp = new List<byte>();

                if (value != null)
                {
                    temp.AddRange(value);
                }

                for (byte i = 0; i < padAmount; i++)
                {
                    temp.Add(
                    Convert.ToByte(
                        Fit.BaseType[baseType].invalidValue));
                }

                field.SetValue(temp.ToArray());
            }
            catch (Exception)
            {
                throw new FitException(
                    "Exception occurred while resizing field to match definition.");
            }
        }
        else
        {
            field.AddValue(Fit.BaseType[baseType].invalidValue);
        }
    }
// ... 

The problem is that for message Num 147 (its not documented, but apparently its the list of the saved sensors) the sensor name (field Num 2, type Fit.String) sometimes has two or more byte[] as value (the first is always the null terminated byte[] for the string and the rest is padding with just one 0 element).

So basically this is the message before entering the while loop (the first element of the value - byte[15] is the string name of the sensor converted to byte[], the second is I suppose padding?):

The size of the message definition is 17 but the size of the current filed value is only 16 so the code tries to add more padding in the while loop. Then the code gets the value of the last field:

 // Get the Last Value of the field
byte[] value = (byte[])field.GetValue(field.GetNumValues() - 1);

But then it actually ads this to the beginning of the field value (`field.SetValue(temp.ToArray()`) instead of appending to the end which essentially just overrides the first element resulting in the following:

Now this results in an infinite loop as the `while (field.GetSize() < size)` will never be false as the "padding" (via the temp variable) actually overrides the first element of the value list and the size never reaches 17 (it will swap between 3 and 16 on each iteration).

I think the code should use the field.SetValue method's overload where an index is provided like this:

field.SetValue(field.GetNumValues()-1, temp.ToArray());
 

This would make sure that the padding is actually appended to the end of the last element instead of the start, increasing the size of the field by every iteration of the while loop (and do not override the actual value on the 0 position).

Let me know if further details is needed.

  • It seems possible that the C# development within Garmin is 100% dead.  The last update of the .csproj file targets .NET 4.6 from 2015, which is now officially unsupported by Microsoft.   The modification times on the files in the SDK are all over two years old, and there seems to be no response to C# bug reports here (possibly nobody to respond).  It's funny too because the website reads as if C# SDK is maybe the primary version, or one of the most core ones anyway, clearly more so than python for instance.   

  • It's funny too because the website reads as if C# SDK is maybe the primary version, or one of the most core ones anyway, clearly more so than python for instance.   

    Exactly my thinkging. All the examples are seemingly written in C#. 

    On the death of the C# dev. while that may be true, its also important to note that if you look back at the changelogs for quite some times the bugs (i.e. the things that do not relate to the update of the filed defintions) that has been fixed and the changes that have been made do not impact the C# SDK. What I am trying to say that there was no need to chnage the C# SDK. Now I would need to look at the other SDK-s to check if such but like the one I dscirbed above would exist but I dont want to sepnd too much time on this :D Actually I reference the SDK in my project (rather than use the precompiled DLL) so I can make as much change as I want :D so for me locally this is fixed.

  • Yes, maybe there have not been many bugs posted regarding the SDK itself.  I documented one a few weeks ago here though that also received no reply.  I did not notice the SDK source code with the download, but I didn't look hard.  I imagined worse case was one could decompile it, but sounds like there's no need.  I guess for the big players they're solving issues as needed (or just have bugs).  But as far as community support from Garmin, it kind of seems non-existent.  It's a great bug report and I guess it would benefit others.

  • The SDKs for all seven languages, including C#, are updated quarterly. Most of the updates are adding new values to existing enumerations or new messages and fields. The code for decoding and encoding files is slow moving across all SDKs. Most of that code has been around for 15 years and it needs to be more than an edge case before we consider making any changes.

    The Visual Studio projects will be removed at some point in the future. The example Visual Studio projects have been superseded by the Cookbook Recipes that use VS Code, and the need to compile the source code into a DLL or class library was made obsolete when the C# SDK was published to Nuget last year.  We don’t know who may still be using the example projects, or what version of Visual Studio they are using. So the safe bet for now is to leave them in the .zip. But they will be removed eventually.  

  • Thank you for the explanation Ben, and the mention of NuGet, which I don't see mentioned on the download page.  I can't comment on how much of an edge case message #147 is. The corruption bug doesn't seem like an edge case, but maybe it is.  An issue tracker would archive such reports well of course.  Some expectation of what .NET and C# versions the SDK is known to work with would be really helpful to provide some confidence when one is chasing problems.  I know C# and .NET strive for high backward compatibility, but knowing that is different from knowing you're using a tested/supported combination. Sorry if I just missed where this is stated.

  • > The Visual Studio projects will be removed at some point in the future. The example Visual Studio projects have been superseded by the Cookbook Recipes that use VS Code, and the need to compile the source code into a DLL or class library was made obsolete when the C# SDK was published to Nuget last year.  We don’t know who may still be using the example projects, or what version of Visual Studio they are using. So the safe bet for now is to leave them in the .zip. But they will be removed eventually.

    Thanks BEN FIT for the above. I am not 100% sure what you are trying to say in the above quoted part of your reply. I use/used the Nuget package and code in VS Code (screenshots are from VS Code). Of course the Nuget distribution system is way superior especially as it handles versioning better an all that. The issue I reported in my view has nothing to do with Nuget or using VS Code vs. VS. 

    I had to move to using the source so I am able step through with the debugger and see what goes where so I can find the reason for my app to hang (after I realised that it is not happening in my part of the code). 

    I would go back to the Nuget if I could as using the FIT SDK source directly makes distribution a ***. Actually I have not yet made my mind up if it even makes sense to push my changes to my public repo or just leave it at Nuget there, for the reason of this issue related to probably an edge case.

    > Most of that code has been around for 15 years and it needs to be more than an edge case before we consider making any changes.

    I acknowledged your statement here, as any change that is done to one SDK needs to be checked whether they remain consistent with the others (which would require resources clearly). Though in my view it should be fairly simple add a unit test for this edge case and run that across the other languages SDKs and see if such issue would be present with those.

  • I think Ben Fit was just reacting to my mention of the old Visual Studio project files.  Visual Studio or VS Code should make no difference to anything (including to which examples are appropriate).