0

I'm teaching myself C and for fun I thought it would be cool to write a small web framework. The code I'm working on at the moment is for registering routes/handlers.

I've run into a segmentation fault with malloc, but strangely only on the fourth time it is called. I've marked the point in the code where the segmentation fault occurs. I'm not sure how to debug it other than wrapping areas of the code with printfs and putss. I've tried using valgrind to debug this, but the segmentation fault doesn't actually happen when I run valgrind. Valgrind does tell me that there is a memory leak stemming from the same malloc, though. So obviously I'm doing something wrong there, but I don't know what.

FYI, destroy_routes is called just before the child process is terminated.

struct route {
    char *path;
    enum method method;
    int(*handler)(struct request *, int sock);
    struct route *next;
};


static struct route *routes;

void
register_route(char *path, enum method method,
               int(*handler)(struct request *, int))
{
    struct route *route;

    if (routes == NULL)
        routes = route = malloc(sizeof(struct route));
    else {
        route = routes;
        while (route->next)
            route = route->next;

        route->next = malloc(sizeof(struct route));
        route = route->next;
    }

    route->path = malloc((strlen(path) + 1) * sizeof(char)); /* <== HERE is where the segmentation fault occurs only on the fourth time */
    strcpy(route->path, path);

    route->method = method;
    route->handler = handler;

    printf("route created: %s, %i, %p\n", route->path, route->method, (void *)route->handler);
}

void
destroy_routes()
{
    struct route *prev;
    int i = 0;
    while (routes) {
        free(routes->path);
        prev = routes;
        routes = routes->next;
        free(prev);
        i++;
    }
    printf("destroyed %i routes\n", i);
}

void
register_routes()
{
    register_route("/post", GET, &do_something);
    register_route("/post", POST, &do_something_else);
    register_route("/post/:id", GET, &do_something);
    register_route("/post/:id/children", POST, &do_something_else);
}
4
  • 1
    routes = route = malloc(sizeof(struct route)); : routes set first time. routes->next is not initialize. Commented Jun 21, 2014 at 16:20
  • @BLUEPIXY it is in the else the second time around or have I been staring at this too long? Commented Jun 21, 2014 at 16:22
  • 1
    @tjb1982 malloc does not zero the memory, so you need to set the next of the last node in the linked list to NULL. You didn't do that anywhere. Commented Jun 21, 2014 at 16:23
  • you need to initialize the members required when you create a struct route by malloc. Commented Jun 21, 2014 at 16:27

1 Answer 1

5

You missed to set the next pointer to NULL. That could be the issue.

route->method = method;
route->handler = handler;
route->next = NULL;
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! That did it. But I don't really understand why. Can you explain it?
Accessing an invalid pointer is undefined behavior. Because of not setting the next to NULL, traversing the list starting from the second invocation of register_route is undefined.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.