Hello,
If this is not the correct list to report a user error, I apologize and will happily redirect my question where ever suitable.
I've been using cffi to make a trivial library to libsensors https://github.com/groeck/lm-sensors and am getting an odd memory fault error when referencing a string value from a groveled struct. After hitting my head against a wall for a day and a half, I thought I'd ask in case it's a simple mistake.
Here's my information:
Running a 64 bit linux install. My local version of the libsensors library is as follows:
elliott@desktop ~ $ file /usr/lib64/libsensors.so.4.4.0 /usr/lib64/libsensors.so.4.4.0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped elliott@desktop ~ $ sensors --version sensors version 3.4.0+git_83cafd29f28d463573750d897014ec7143217ae5 with libsensors version 3.4.0+git_83cafd29f28d463573750d897014ec7143217ae5
I'm using a fairly recent version of sbcl built from source that (apparently) passed all of the tests after the build:
CL-USER> (lisp-implementation-version) "1.4.6.140-f8d5864d0"
My version of cffi appears to be the latest:
CL-USER> (slot-value (asdf:find-system :cffi) 'asdf:version) "0.19.0"
My system uses cffi-grovel and defines the following structs:
(cstruct sensors-bus-id "sensors_bus_id" (type "type" :type :short) (nr "nr" :type :short))
(cstruct sensors-chip-name "sensors_chip_name" (prefix "prefix" :type :string) (bus "bus" :type (:struct sensors-bus-id)) (address "addr" :type :int) (path "path" :type :string))
These are based upon the definitions in sensors/sensors.h: https://github.com/groeck/lm-sensors/blob/master/lib/sensors.h
After asdf loading the system, the following groveler definitions are created (had to dig these out of the cached build files):
(cffi:defcstruct (sensors-bus-id :size 4) (type :short :offset 0) (nr :short :offset 2)) (cl:defconstant size-of-sensors-bus-id (cffi:foreign-type-size '(:struct sensors-bus-id))) (cffi:defcstruct (sensors-chip-name :size 24) (prefix :string :offset 0) (bus (:struct sensors-bus-id) :offset 8) (address :int :offset 12) (path :string :offset 16)) (cl:defconstant size-of-sensors-chip-name (cffi:foreign-type-size '(:struct sensors-chip-name)))
All of the above appears to be correct, so I proceed to load the library:
(define-foreign-library libsensors (:unix (:or "libsensors.so.4" "libsensors.so")) (t (:default "libsensors.so"))) (use-foreign-library libsensors)
No issues, so I define a c function from the c header file that parses a sensor chip name-string into a struct:
(defcfun ("sensors_parse_chip_name" cffi-sensors-parse-chip-name) :int "Parse a chip name to the internal representation. Return 0 on success, <0 on error." (orig-name :string) (res (:pointer (:struct sensors-chip-name))))
Which is based upon the following header function declaration:
int sensors_parse_chip_name(const char *orig_name, sensors_chip_name *res);
Then I implement a simple call to print out the parsed values (not including the bus):
(defun test-sensors-parse-chip-name (string) (with-foreign-object (name '(:struct sensors-chip-name)) (unless (= 0 (cffi-sensors-parse-chip-name string name)) (error "Failed to parse: ~A" string)) (with-foreign-slots ((prefix address path) name (:struct sensors-chip-name)) (format t "~%Prefix: '~A'" prefix) (format t "~%Address: '~A'" address) (format t "~%Path: '~A'" path))))
The above when executed gives the following output before the error:
CL-LMSENSORS> (test-sensors-parse-chip-name "atk0110-acpi-0")
Prefix: 'atk0110' Address: '0'
And once it tries to access the path variable, it gives the following error (sorry a lot rolls off the screen):
Unhandled memory fault at #xE71B7. [Condition of type SB-SYS:MEMORY-FAULT-ERROR]
Restarts: 0: [RETRY] Retry SLIME REPL evaluation request. 1: [*ABORT] Return to SLIME's top level. 2: [ABORT] abort thread (#<THREAD "repl-thread" RUNNING {1002207F93}>)
Backtrace: 0: (CFFI::FOREIGN-STRING-LENGTH #.(SB-SYS:INT-SAP #X000E71B7) :ENCODING :UTF-8 :OFFSET 0) Locals: #:.DEFAULTING-TEMP. = :UTF-8 #:.DEFAULTING-TEMP.#1 = 0 #:N-SUPPLIED-0 = 1 POINTER = #.(SB-SYS:INT-SAP #X000E71B7) 1: (FOREIGN-STRING-TO-LISP #.(SB-SYS:INT-SAP #X000E71B7) :OFFSET 0 :COUNT NIL :MAX-CHARS 4611686018427387900 :ENCODING :UTF-8$ Locals: #:.DEFAULTING-TEMP. = 0 #:.DEFAULTING-TEMP.#1 = NIL #:.DEFAULTING-TEMP.#2 = 4611686018427387900 #:.DEFAULTING-TEMP.#3 = :UTF-8 ENCODING = :UTF-8 #:N-SUPPLIED-0 = 1 POINTER = #.(SB-SYS:INT-SAP #X000E71B7) 2: ((:METHOD TRANSLATE-FROM-FOREIGN (T CFFI::FOREIGN-STRING-TYPE)) #.(SB-SYS:INT-SAP #X000E71B7) #<CFFI::FOREIGN-STRING-TYPE $ 3: (TEST-SENSORS-PARSE-CHIP-NAME "atk0110-acpi-0")
My guess is I'm not defining the (:struct sensors-chip-name) correctly, so that when sensors_parse_chip_name writes values into the struct, it somehow overlaps into the path string.
When looking at the source for sensors_parse_chip_name I've noticed that it does not set or access the path value at all. So I decided to write a small c program to test the native behavior:
elliott@desktop ~ $ cat test-sensors.c #include <stdio.h> #include <stdlib.h> #include "sensors/sensors.h"
int main( ) {
//sensors_init( NULL );
struct sensors_chip_name name;
int return_value = sensors_parse_chip_name( "atk0110-acpi-0", &name); if ( return_value != 0 ) { printf( "Failed to get a good return value." ); exit( return_value ); }
printf( "Printing the prefix: '%s'\n", name.prefix ); printf( "Address: '%i'\n", name.addr ); printf( "Printing path value: '%s'\n", name.path ); printf ("\n exiting..." );
exit( 0 ); } elliott@desktop ~ $ gcc test-sensors.c -l sensors -o test-sensors elliott@desktop ~ $ ./test-sensors Printing the prefix: 'atk0110' Address: '0' Printing path value: ''
exiting...
No problems there, so I assume that the issue is all my lack of cffi-fu training. Any pointers (yes, pun intended) would be appreciated... sorry for such a long read, but I hope it helps to have the background. At the very least it helped me to frame the issue in my mind by writing this.
Regards, Elliott