cpointersudev

Using sd-device enumerating devices result in seg fault



#include <stdio.h>
#include <stdlib.h>
#include <systemd/sd-device.h>
int main() {
    sd_device *device;
    sd_device_enumerator *enumerator =NULL;
    const char **subsystem =NULL;
    // *subsystem = malloc(sizeof(char *));
    *subsystem = malloc(500);
    if (subsystem == NULL)
        printf("ohh");
    // Create a device enumerator
    int r = sd_device_enumerator_new(&enumerator);
    if (r< 0)
        printf("unable to create instance");
        printf("%d\n",r);
    //sd_device_enumerator_scan(enumerator);
    for (device = sd_device_enumerator_get_device_first(enumerator); device != NULL;
         device = sd_device_enumerator_get_device_next(enumerator)) {
        
            r = sd_device_get_subsystem(device, subsystem);
            if (r < 0) 
            printf("error in subsystem");
                
                printf(" %s\n", subsystem);
                if (subsystem != NULL) 
                free((char *)subsystem); // free the previous subsystem name
                            
            
}
}

compiling above code results in seg fault

gcc -o dev_enum test2.c -lsystemd is used to compile Please help


Solution

  • The cause is a null pointer dereference, which invokes undefined behavior:

    const char **subsystem =NULL;
    // *subsystem = malloc(sizeof(char *));
    *subsystem = malloc(500);
    

    In the 3rd line, subsystem is being dereferenced, which was a null pointer.

    According to the man page for sd_device_get_subsystem(), the second argument needs to be a char **, so you just define subsystem as a char *, and pass &subsystem as the second argument to sd_device_get_subsystem().

    Though, I believe that the function is going to change the pointed to pointer to point to the kernel subsystem of the specified device record, and the allocated 500 bytes are going to be lost when it does so, and what's actually required here is just:

    char *subsystem = NULL;
    r = sd_device_get_subsystem(device, &subsystem);
    

    The man page is quiet on its working, and does not explain anything more than what the function returns.

    The man page doesn't say anything about dynamic allocation, so I would assume that it is a static buffer that subsystem would be set to point to and there's no need of any malloc()/free() in the code.

    Some other problems:

    Edit: This is how it is being used in libsystemd's code:

    const char *subsystem;
    
    r = sd_device_get_subsystem(device, &subsystem);
    

    Doing some quick Google searches always help. :)