1

I am getting segmentation fault when I try to pass char array to const char *

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static char *
get_valid_date_format(const char *date) {
    struct tm result;
    char *ret;
    char **f;
    
    char *formats[] = {"%Y", "%Y-%m", "%y-%m", "%Y-%m-%d", "%y-%m-%d",
        "%Y%m%d", "%y%m%d", "%Y-%m-%d %T", "%y-%m-%d %T", "%Y%m%d%H%M%S",
        "%y%m%d%H%M%S", "%Y-%m-%dT%T", "%y-%m-%dT%T", "%Y-%m-%dT%TZ",
        "%y-%m-%dT%TZ", "%Y-%m-%d %TZ", "%y-%m-%d %TZ", "%Y%m%dT%TZ",
        "%y%m%dT%TZ", "%Y%m%d %TZ", "%y%m%d %TZ", NULL };
        
    
    memset(&result, 0, sizeof(result));
    for (f = formats; f && *f; f++)
    {
        printf("check format: %s\n", *f);
        ret = strptime(date, *f, &result);
        if (ret && *ret == '\0')
        {
            printf("found Format: %s\n\n", *f);
            return *f;
        }
    }

    return (char *)0;
}


void main()
{
    char *format;
    char *date = "2020-07-25T00:10:58";
    char date2[] = "2020-07-25T00:10:58";
    char *date3 = "2020-07-25T00:10:58.000Z";
    
    date2[3] = '1';

    format = get_valid_date_format(date2);
    if (format == NULL) {
        printf("format is NULL\n");
        return;
    } else {
        printf("format found = %s\n", format);
    }
}

If I call get_valid_date_format(date), then it works fine. So calling with char * works find but when passing char[] then I get segmentation fault. I need to use array as I need to modify it before calling get_valid_date_format.

  • formats[] is not used outside get_valid_date_format(). In the main, I actually don't need to know the actual format but just whether the format is valid or not. The code works as I have it if I call get_valid_date_format(date) but not when I call get_valid_date_format(date2). When I pass an array date2[] instead of pointer *date, then I get segmentation fault at strptime() function call. I think the problem is trying to figure out how to pass the array date2[] to get_valid_date_format, so that strptime() is happy. – Piyush Bhagat Jul 07 '20 at 23:57
  • Where are your `#include`s? – M. Nejat Aydin Jul 08 '20 at 00:09
  • @M.NejatAydin updated the code with the #include s – Piyush Bhagat Jul 08 '20 at 00:14
  • Write in the first line: `#define _XOPEN_SOURCE 700` and google for `The _XOPEN_SOURCE Feature Test Macro`. – M. Nejat Aydin Jul 08 '20 at 00:18
  • 1
    Did you read your compiler warnings? – klutt Jul 08 '20 at 00:27
  • I had to use two `#define` statements, as in this answer https://stackoverflow.com/a/15334600/11831920 – Jonathon Anderson Jul 08 '20 at 00:30
  • What compiler and system are you using? What compiler flags are you using? I ran this program on macOS X 10.14 with Clang v.11.0.0 without any problem (well, I had to change your bad definition of main(), remove the unecessary return; and make formats static). – Jeff Szuhay Jul 08 '20 at 01:01
  • @M.NejatAydin adding #define _XOPEN_SOURCE seems to have taken care of the segmentation fault. Thank you. – Piyush Bhagat Jul 08 '20 at 01:20

1 Answers1

2

As M. Nejat Aydin commented, strptime is not a standard C function, it comes from BSD and is part of the POSIX standard used by Unix. To ensure it is loaded, add -D_XOPEN_SOURCE=700 to load X/Open and POSIX extensions.


Compiler warnings will tell you about a host of other potential issues. If you're using a command line compiler like gcc or clang, you have to run compiler warnings on. There's a host of options, I recommend -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c11 -pedantic.

char *formats[] declares an array of char * local to the function. You're returning one of those elements. Normally returning a local variable can cause a memory fault because that memory can be deallocated when the function exits. But formats consists of string literals which are not deallocated. But you've incorrectly declared them writable char *. You can go from non-const to const, but you can't go from const to non-const.

formats should be const char *formats[], an array of read-only const char *. They are read-only string literals which are never deallocated (static) and can be safely returned from the function. For belt-and-suspenders, declare formats static because it only needs ever to be allocated once.

Similarly, get_valid_date_format should return static const char *, format should be const char *, and f is a const char **.

Though some compilers will allow void main, that is not valid. main returns an int.

char *foo = "..."; is incorrect. It is a char foo[] = "..." or a const char *foo if it's read-only. This applies to all your date variables. const char *date = ..., const char *date3 = "..." and because you modify date2, char date2[] = ....

There is no need to check if f is true in the loop, just *f, but it doesn't hurt.

return (char *)0; is better written as return NULL;

There is no need to initialize result with memset since you're just passing it to strptime which will overwrite with its own values.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • By declaring the function `static char * get_valid_date_format` you are telling the compiler that the function `get_valid_data_format` may not be called from outside the compilation unit. It does NOT return a static pointer. Instead, declare `static char* formats[] = ` – Jeff Szuhay Jul 08 '20 at 01:05
  • @JeffSzuhay Thanks for clarifying. – Schwern Jul 08 '20 at 01:09
  • 1
    No, there is no problem with `formats`. The returned value is a pointer to the first character of a `string literal` and `string literals` have `static storage duration`. – M. Nejat Aydin Jul 08 '20 at 01:13
  • @M.NejatAydin Are you sure? `test.c:13:24: warning: initializing 'char *' with an expression of type 'const char [11]' discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]` – Schwern Jul 08 '20 at 01:16
  • Are you using c++ compiler? – M. Nejat Aydin Jul 08 '20 at 01:17
  • @M.NejatAydin No, clang in C11 mode. `clang -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c11 -pedantic -g` – Schwern Jul 08 '20 at 01:18
  • 1
    @Schwern Thanks for these suggestions. Adding #define _XOPEN_SOURCE fixed the segmentation issue but these are good suggestions that I will take into account. – Piyush Bhagat Jul 08 '20 at 01:23
  • `-Wwrite-strings` flag gives the same warning with the line `char *date = "2020-07-25T00:10:58";` as well. There is no problem with the declaration. Attempting to modify a sting literal is a problem, but this is not the case here. The problem with the code is that the compiler doesn't see the declaration of `strptime` function unless _XOPEN_SOURCE is `#define`d. See my comment to the original question. – M. Nejat Aydin Jul 08 '20 at 01:28
  • @M.NejatAydin Ahh. You should write that as an answer. – Schwern Jul 08 '20 at 01:31
  • I am too lazy right now :) And this is a Posix question rather than C. strptime is a Posix function. – M. Nejat Aydin Jul 08 '20 at 01:33