0

When expanding the functionality of some code from an open-source library, I encountered a strange Segmentation Fault error upon attempting to return an enum value from a function.

The library decodes NMEA messages (irrelevant to the problem), and one function which determines the type of message should return a number as defined by an enum.

The enum is defined:

enum minmea_sentence_id {
    MINMEA_INVALID = -1,
    MINMEA_UNKNOWN = 0,
    MINMEA_SENTENCE_GBS,
    MINMEA_SENTENCE_GGA,
    MINMEA_SENTENCE_GLL,
    MINMEA_SENTENCE_GSA,
    MINMEA_SENTENCE_GST,
    MINMEA_SENTENCE_GSV,
    MINMEA_SENTENCE_RMC,
    MINMEA_SENTENCE_VTG,
    MINMEA_SENTENCE_ZDA,
    MINMEA_SENTENCE_HDT,
    MINMEA_SENTENCE_ROT,
    MINMEA_SENTENCE_VDBG,
    MINMEA_SENTENCE_ATTSTAT,
    MINMEA_SENTENCE_RTKSTAT,
};

With the first 11 names being from the original library, and with the last 5 names being added by me.

The function is defined:

enum minmea_sentence_id minmea_get_sentence_id(const char *sentence, bool strict)
{
    if (!minmea_check(sentence, strict))
        return MINMEA_INVALID;

    char type[6];
    if (!minmea_scan(sentence, "t", type))
        return MINMEA_INVALID;

    if (!strcmp(type+2, "GBS"))
        return MINMEA_SENTENCE_GBS;
    if (!strcmp(type+2, "GGA"))
        return MINMEA_SENTENCE_GGA;
    if (!strcmp(type+2, "GLL"))
        return MINMEA_SENTENCE_GLL;
    if (!strcmp(type+2, "GSA"))
        return MINMEA_SENTENCE_GSA;
    if (!strcmp(type+2, "GST"))
        return MINMEA_SENTENCE_GST;
    if (!strcmp(type+2, "GSV"))
        return MINMEA_SENTENCE_GSV;
    if (!strcmp(type+2, "RMC"))
        return MINMEA_SENTENCE_RMC;
    if (!strcmp(type+2, "VTG"))
        return MINMEA_SENTENCE_VTG;
    if (!strcmp(type+2, "ZDA"))
        return MINMEA_SENTENCE_ZDA;
    if (!strcmp(type+2, "HDT"))
        return MINMEA_SENTENCE_HDT;
    if (!strcmp(type+2, "ROT"))
        return MINMEA_SENTENCE_ROT;
    if (!strncmp(type, "VDBG", 4))
        return MINMEA_SENTENCE_VDBG;
    if (!strcmp(type, "ATTSTAT"))
        return MINMEA_SENTENCE_ATTSTAT;
    if (!strcmp(type, "RTKSTAT"))
        return MINMEA_SENTENCE_RTKSTAT;

    return MINMEA_UNKNOWN;
}

When the function is called with this line (normal_VDBG is just an example string message):

enum minmea_sentence_id id = minmea_get_sentence_id(normal_VDBG, true);

a segmentation error is thrown: SIGSEGV

Of particular strangeness: when the function is called with one of the NMEA Sentences already included in the library, e.g. a GGA message, the segmentation fault is not thrown and the code executes as-expected. The error is only thrown when using one of the message types I've added to the enum.

The segmentation error can be fixed by changing the function definition to this:

enum minmea_sentence_id minmea_get_sentence_id(const char *sentence, bool strict)
{
    enum minmea_sentence_id returnVal;

    if (!minmea_check(sentence, strict)) {
        returnVal = MINMEA_INVALID;
        return returnVal;
    }

    char type[6];
    if (!minmea_scan(sentence, "t", type)) {
        returnVal = MINMEA_INVALID;
        return returnVal;
    }
    if (!strcmp(type+2, "GBS")) {
        returnVal = MINMEA_SENTENCE_GBS;
        return returnVal;
    }
    if (!strcmp(type+2, "GGA")) {
        returnVal = MINMEA_SENTENCE_GGA;
        return returnVal;
    }
    if (!strcmp(type+2, "GLL")) {
        returnVal = MINMEA_SENTENCE_GLL;
        return returnVal;
    }
    if (!strcmp(type+2, "GSA")) {
        returnVal = MINMEA_SENTENCE_GSA;
        return returnVal;
    }
    if (!strcmp(type+2, "GST")) {
        returnVal = MINMEA_SENTENCE_GST;
        return returnVal;
    }
    if (!strcmp(type+2, "GSV")) {
        returnVal = MINMEA_SENTENCE_GSV;
        return returnVal;
    }
    if (!strcmp(type+2, "RMC")) {
        returnVal = MINMEA_SENTENCE_RMC;
        return returnVal;
    }
    if (!strcmp(type+2, "VTG")) {
        returnVal = MINMEA_SENTENCE_VTG;
        return returnVal;
    }
    if (!strcmp(type+2, "ZDA")) {
        returnVal = MINMEA_SENTENCE_ZDA;
        return returnVal;
    }
    if (!strcmp(type+2, "HDT")) {
        returnVal = MINMEA_SENTENCE_HDT;
        return returnVal;
    }
    if (!strcmp(type+2, "ROT")) {
        returnVal = MINMEA_SENTENCE_ROT;
        return returnVal;
    }
    if (!strncmp(type, "VDBG", 4)) {
        returnVal = MINMEA_SENTENCE_VDBG;
        return returnVal;
    }
    if (!strcmp(type, "ATTSTAT")) {
        returnVal = MINMEA_SENTENCE_ATTSTAT;
        return returnVal;
    }
    if (!strcmp(type, "RTKSTAT")) {
        returnVal = MINMEA_SENTENCE_RTKSTAT;
        return returnVal;
    }

    returnVal = MINMEA_UNKNOWN;
    return returnVal;
}

With this change, there is no more fault on any message types.

The question: does anyone know why this would be the case? Shouldn't returning an enum name from the function be essentially the same as returning an integer? And regardless, why would it cause a Segmentation Fault of all things?

Thanks for the assistance!

Ineruditus
  • 51
  • 4
  • 4
    Your type array can hold a string of at most 5 chars (plus the null terminator), yet some of your comparison strings are 7 chars long. – Avi Berger Dec 05 '22 at 00:59
  • 3
    As to why your change impacted your symptoms - you evidently have bug(s) in your code and that change affected the consequences of that bug, masking the particular symptom you were seeing. Doesn't mean the bug is fixed or wont produce some other symptom. Presume your code is still broken. – Avi Berger Dec 05 '22 at 01:10
  • 2
    Sounds like minmea_scan() makes assumptions about its 'type' parameter (i.e the size of the array), which you are exceeding. So possibly not a bug in your code per-se, but a (possibly undocumented) restriction in the existing code. – pmacfarlane Dec 05 '22 at 01:19
  • The question is - what does minmea_scan() put in the 'type' array? If it is a zero-terminated string, you can compare that with longer strings. If it is failing to zero-terminate it, or overflowing the array, you could get a segfault. – pmacfarlane Dec 05 '22 at 01:24
  • @AviBerger Yep, you're definitely correct. Can you post this as an answer so I can mark it as correct? – Ineruditus Dec 05 '22 at 01:27

0 Answers0