#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
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:
malloc()
and family return a null pointer on failure. Failing to check for it risks invoking undefined behavior by a subsequent null pointer dereference. Printing "ooh"
ain't going to fix it.
free()
expects a generic void *
that is implicitly converted to and from any other pointer type. There's no need to cast its argument to a char *
.
Errors aren't handled by printing logs to stdout
. You can hardly recover from a malloc()
failure, or recover from sd_device_enumerator_new()
failure by calling sd_device_enumerator_get_device_first()
right after it. Simply exit.
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. :)