pythoncpointersctypesdigital-persona-sdk

calling C program function in python - Segmentation fault


So I have a C program that I am running from Python. But am getting segmentation fault error. when I run the C program alone, it runs fine. The C program interfaces a fingerprint sensor using the fprint lib.

#include <poll.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdio.h>
#include <libfprint/fprint.h>



int main(){

struct fp_dscv_dev **devices;
struct fp_dev *device;
struct fp_img **img;

int r;
r=fp_init();

if(r<0){
    printf("Error");
    return 1;
}

devices=fp_discover_devs();
if(devices){
    device=fp_dev_open(*devices);

    fp_dscv_devs_free(devices);
}
if(device==NULL){
    printf("NO Device\n");
    return 1;
}else{
    printf("Yes\n");
   
}


int caps;

caps=fp_dev_img_capture(device,0,img);

printf("bloody status %i \n",caps);

    //save the fingerprint image to file. ** this is the block that 
     causes the segmentation fault.

    int imrstx;
    imrstx=fp_img_save_to_file(*img,"enrolledx.pgm");
    fp_img_free(*img);


fp_exit();
return 0;
}

the python code

from ctypes import *
so_file = "/home/arkounts/Desktop/pythonsdk/capture.so"
my_functions = CDLL(so_file)

a=my_functions.main()
print(a)
print("Done")

The capture.so is built and accessed in python. But calling from python, I get a Segmentation fault. What could be my problem?

Thanks alot


Solution

  • Although I am unfamiliar with libfprint, after taking a look at your code and comparing it with the documentation, I see two issues with your code that can both cause a segmentation fault:


    First issue:

    According to the documentation of the function fp_discover_devs, NULL is returned on error. On success, a NULL-terminated list is returned, which may be empty.

    In the following code, you check for failure/success, but don't check for an empty list:

    devices=fp_discover_devs();
    if(devices){
        device=fp_dev_open(*devices);
    
        fp_dscv_devs_free(devices);
    }
    

    If devices is non-NULL, but empty, then devices[0] (which is equivalent to *devices) is NULL. In that case, you pass this NULL pointer to fp_dev_open. This may cause a segmentation fault.

    I don't think that this is the reason for your segmentation fault though, because this error in your code would only be triggered if an empty list were returned.


    Second issue:

    The last parameter of fp_dev_img_capture should be a pointer to an allocated variable of type struct fp_img *. This tells the function the address of the variable that it should write to. However, with the code

    struct fp_img **img;
    [...]
    caps=fp_dev_img_capture(device,0,img);
    

    you are passing that function a wild pointer, because img does not point to any valid object. This can cause a segmentation fault as soon as the wild pointer is dereferenced by the function or cause some other kind of undefined behavior, such as overwriting other variables in your program.

    I suggest you write the following code instead:

    struct fp_img *img;
    [...]
    caps=fp_dev_img_capture(device,0,&img);
    

    Now the third parameter is pointing to a valid object (to the variable img).

    Since img is now a single pointer and not a double pointer, you must pass img instead of *img to the functions fp_img_save_to_file and fp_img_free.

    This second issue is probably the reason for your segmentation fault. It seems that you were just "lucky" that your program did not segfault as a standalone program.