Get struct* from out parameter in Chibi Scheme FFI bindings - ffi

Can you get a struct * from the out parameter of a C function in Chibi Scheme?
I'm trying to get a struct archive_entry * from this C function:
int archive_read_next_header(
struct archive *archive,
struct archive_entry **out_entry);
In C one would do it like this:
struct archive_entry *entry;
archive_read_next_header(archive, &entry);
My Chibi FFI code is:
(define-c-struct archive)
(define-c-struct archive_entry)
(define-c int
archive-read-next-header
(archive (result reference archive_entry)))
But it's not generating the right C code to get the archive_entry. I
think reference is the wrong thing to use. I also tried pointer
but it didn't work either.

I still don't know if it can be done directly.
But I was able to work around the problem by writing a custom thunk function in C:
(c-declare "
struct archive_entry *my_archive_read(struct archive *a, int *out_errcode) {
struct archive_entry *entry;
int errcode;
*out_errcode = errcode = archive_read_next_header(a, &entry);
return (errcode == ARCHIVE_OK) ? entry : NULL;
}")
(define-c archive_entry my-archive-read (archive (result int)))
So the key is that Scheme doesn't need to deal with any double-indirection (**) in this version. The C code converts double-indirection into single-indirection for Scheme so it all works out.
Example usage from a Scheme program:
(let ((archive (my-archive-open filename)))
(disp "archive" archive)
(let* ((return-values (my-archive-read archive))
(entry (car return-values))
(errcode (cadr return-values)))
(display entry)
(newline)))
I copied the technique from the chibi-sqlite3 bindings where they face a similar problem having to get a sqlite3_stmt * from an out parameter:
(c-declare
"sqlite3_stmt* sqlite3_prepare_return(sqlite3* db, const char* sql, const int len) {
sqlite3_stmt* stmt;
char** err;
return sqlite3_prepare_v2(db, sql, len, &stmt, NULL) != SQLITE_OK ? NULL : stmt;
}
")
(define-c sqlite3_stmt (sqlite3-prepare "sqlite3_prepare_return") (sqlite3 string (value (string-length arg1) int)))

Related

Please advise with libcsv. I need to read only first row

I had successfully used libcsv to parse CSV files. Fast and simple to use, I tell you. But now comes a situation where I am a little stuck. Being able to parse file as whole, now I need to parse only first row.
My basic usage(not too far from the official documentation) is following:
typedef struct data_t {
<...>
} data_t;
...
void cb_f(void *s, size_t len, void *data) {
...
}
void cb_r(int c, void *data) {
((counts*)data)->rows++;
}
...
struct csv_parser p;
data_t data;
...
if(csv_parse(&p, buf, fsize, cb_f, cb_r, &data) != fsize) {
fprintf(stderr, " * while parsing file: %s\n", csv_strerror(csv_error(&p)) );
return 1;
}
...
csv_fini(&p, NULL, NULL, NULL);
Now I need to somehow stop the parser after it had processed the first row of a CSV file.
I did try to call csv_fini(&p, NULL, NULL, NULL); in the row callback, cb_r, early. No luck, the parser stops only after parsing whole buffer.
Any suggestions of how to change the libcsv parser operation mode ?

Set up a specific key for RSA OpenSSL

I'm currentlyt trying to implement some test vectors for RSA implementations, and I wanted to test them over OpenSSL v1.1.0f implementation. However, when I try to set up the key (for e, n p, q or d), I have the following error :
erreur : dereferencing pointer to incomplete type « RSA {alias struct rsa_st} »
My code is the following :
int rsa_encrypt(byte *in, size_t in_len, byte *out, const char *n, const char *e, char padding){
int err = -1;
RSA *keys = NULL;
keys = RSA_new();
BN_hex2bn(&keys->n, n); // error here
BN_hex2bn(&keys->e, e); // and here
out = malloc(RSA_size(keys));
if (padding == OAEP ) {
err = RSA_public_encrypt(in_len, in, out, keys, RSA_PKCS1_OAEP_PADDING);
}
else if (padding == v1_5) {
err = RSA_public_encrypt(in_len, in, out, keys, RSA_PKCS1_PADDING);
}
RSA_free(keys);
return err;
}
Where n and e are a string representing my parameter in hexa.
I've looked for the structure corresponding to the RSA type, and found this.
I don't understand why I can't set up n and e... Any idea ?
The OpenSSL structs are opaque in 1.1.x, you can't talk about their fields. Among other things, it allows for new struct fields to be added during servicing releases, since caller code can't know the field offset.
For 1.1.x you'd need to do something akin to
BN* bnN = NULL;
BN* bnE = NULL;
RSA* keys = RSA_new();
BN_hex2bn(&bnN, n);
BN_hex2bn(&bnE, e);
RSA_set0_key(keys, bnN, bnE, NULL);
...
RSA_free(keys);
// do not free bnN or bnE, they were freed by RSA_free.
Note that I left out the requisite error checking.

sending a struct array with sun rpc from server to client

how can i correctly send a struct from the server to the client in ansi-c sun-rpc?
in my test.x IDL file i defined a struct cluster with a string and an int
and a type clusters which is a variable-length array of cluster elements:
struct cluster {
string name<255>;
int debuglevel;
};
typedef cluster clusters<32>;
i then changed the stubs generated by rpcgen like
test_server.c
clusters *
test_1_svc(void *argp, struct svc_req *rqstp)
{
static clusters result;
cluster cl1, cl2;
cl1.name="cl1";
cl1.debuglevel="1";
cl2.name="cl2";
cl2.debuglevel="2";
cluster clist[2];
clist[0]=cl1;
clist[1]=cl2;
result.clusters_len = 2;
result.clusters_val = &clist;
/*
* insert server code here
*/
return(&result);
}
and test_client.c
test_prog_1( char* host )
{
CLIENT *clnt;
clusters *result_1;
char* test_1_arg;
clnt = clnt_create(host, test_PROG, test_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror(host);
exit(1);
}
result_1 = test_1((void*)&test_1_arg, clnt);
if (result_1 == NULL) {
clusters* rec_cls = malloc(2*sizeof(struct cluster));
if(xdr_clusters(&result_1, rec_cls)){
printf("got xdr_clusters");
}
clnt_perror(clnt, "call failed:");
}
clnt_destroy( clnt );
}
Both compile, but the server often segfaults after one or two request runs by the client and on the clientside the xdr_clusters function never returns true. It seems like some kind of memory mismanagement and I'm also not sure if I'm handling the serialization on the server-side correctly.
I just filled result.clusters_len and result.clusters_val with the appropiate values like they are defined in test.h (by rpcgen):
typedef struct {
u_int clusters_len;
cluster *clusters_val;
} clusters;
Do I have to make use of xdr_clusters on the server side for this to correctly serialize the result?
thank you
okay, i figured my mistakes, lets summarize them:
know how to initialize an int correctly (without the quotes of course...)
forget about that clist nonsense, just malloc the internal pointer of the result struct directly
read the damn compiler warnings: when it tells you, that there are functions declared implicitly and you didn't want implicit declarations, then there is possibly something missing, in my case i needed to include stdlib.h and stdio.h to get malloc, printf and exit functions for server and client stubs.
on the clientside: why should we do anything except throwing an error if the result is NULL? see the new client code below to check correct result printing
test_server.c
test_1_svc(void *argp, struct svc_req *rqstp){
static clusters result;
cluster cl1, cl2;
cl1.name="cl1";
cl1.debuglevel=1;
cl2.name="cl2";
cl2.debuglevel=2;
result.clusters_len = 2;
result.clusters_val = malloc(2*sizeof(struct cluster));
result.clusters_val[0]=cl1;
result.clusters_val[1]=cl2;
return(&result);
}
test_client.c
test_prog_1( char* host )
{
CLIENT *clnt;
clusters *result_1;
char* test_1_arg;
clnt = clnt_create(host, test_PROG, test_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror(host);
exit(1);
}
result_1 = test_1((void*)&test_1_arg, clnt);
if (result_1 == NULL) {
clnt_perror(clnt, "call failed:");
}else{
printf("I got %d cluster structs in an array\n",result_1->clusters_len);
int j;
for(j=0;j<result_1->clusters_len;j++){
printf("cluster #%d: %s#runlevel %d\n",j,result_1->clusters_val[j].name,result_1->clusters_val[j].debuglevel);
}
}
clnt_destroy( clnt );
}
as a result, we get some nice values on the clientside printed
and of course no segfaults anymore on the serverside:
lars$ ./test_client localhost
I got 2 cluster structs in an array
cluster #0: cl1#runlevel 1
cluster #1: cl2#runlevel 2

Find pathname from dlopen handle on OSX

I have dlopen()'ed a library, and I want to invert back from the handle it passes to me to the full pathname of shared library. On Linux and friends, I know that I can use dlinfo() to get the linkmap and iterate through those structures, but I can't seem to find an analogue on OSX. The closest thing I can do is to either:
Use dyld_image_count() and dyld_get_image_name(), iterate over all the currently opened libraries and hope I can guess which one corresponds to my handle
Somehow find a symbol that lives inside of the handle I have, and pass that to dladdr().
If I have apriori knowledge as to a symbol name inside of the library I just opened, I can dlsym() that and then use dladdr(). That works fine. But in the general case where I have no idea what is inside this shared library, I would need to be able to enumerate symbols to do that, which I don't know how to do either.
So any tips on how to lookup the pathname of a library from its dlopen handle would be very much appreciated. Thanks!
Here is how you can get the absolute path of a handle returned by dlopen.
In order to get the absolute path, you need to call the dladdr function and retrieve the Dl_info.dli_fname field.
In order to call the dladdr function, you need to give it an address.
In order to get an address given a handle, you have to call the dlsym function with a symbol.
In order to get a symbol out of a loaded library, you have to parse the library to find its symbol table and iterate over the symbols. You need to find an external symbol because dlsym only searches for external symbols.
Put it all together and you get this:
#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <mach-o/nlist.h>
#import <stdio.h>
#import <string.h>
#ifdef __LP64__
typedef struct mach_header_64 mach_header_t;
typedef struct segment_command_64 segment_command_t;
typedef struct nlist_64 nlist_t;
#else
typedef struct mach_header mach_header_t;
typedef struct segment_command segment_command_t;
typedef struct nlist nlist_t;
#endif
static const char * first_external_symbol_for_image(const mach_header_t *header)
{
Dl_info info;
if (dladdr(header, &info) == 0)
return NULL;
segment_command_t *seg_linkedit = NULL;
segment_command_t *seg_text = NULL;
struct symtab_command *symtab = NULL;
struct load_command *cmd = (struct load_command *)((intptr_t)header + sizeof(mach_header_t));
for (uint32_t i = 0; i < header->ncmds; i++, cmd = (struct load_command *)((intptr_t)cmd + cmd->cmdsize))
{
switch(cmd->cmd)
{
case LC_SEGMENT:
case LC_SEGMENT_64:
if (!strcmp(((segment_command_t *)cmd)->segname, SEG_TEXT))
seg_text = (segment_command_t *)cmd;
else if (!strcmp(((segment_command_t *)cmd)->segname, SEG_LINKEDIT))
seg_linkedit = (segment_command_t *)cmd;
break;
case LC_SYMTAB:
symtab = (struct symtab_command *)cmd;
break;
}
}
if ((seg_text == NULL) || (seg_linkedit == NULL) || (symtab == NULL))
return NULL;
intptr_t file_slide = ((intptr_t)seg_linkedit->vmaddr - (intptr_t)seg_text->vmaddr) - seg_linkedit->fileoff;
intptr_t strings = (intptr_t)header + (symtab->stroff + file_slide);
nlist_t *sym = (nlist_t *)((intptr_t)header + (symtab->symoff + file_slide));
for (uint32_t i = 0; i < symtab->nsyms; i++, sym++)
{
if ((sym->n_type & N_EXT) != N_EXT || !sym->n_value)
continue;
return (const char *)strings + sym->n_un.n_strx;
}
return NULL;
}
const char * pathname_for_handle(void *handle)
{
for (int32_t i = _dyld_image_count(); i >= 0 ; i--)
{
const char *first_symbol = first_external_symbol_for_image((const mach_header_t *)_dyld_get_image_header(i));
if (first_symbol && strlen(first_symbol) > 1)
{
handle = (void *)((intptr_t)handle | 1); // in order to trigger findExportedSymbol instead of findExportedSymbolInImageOrDependentImages. See `dlsym` implementation at http://opensource.apple.com/source/dyld/dyld-239.3/src/dyldAPIs.cpp
first_symbol++; // in order to remove the leading underscore
void *address = dlsym(handle, first_symbol);
Dl_info info;
if (dladdr(address, &info))
return info.dli_fname;
}
}
return NULL;
}
int main(int argc, const char * argv[])
{
void *libxml2 = dlopen("libxml2.dylib", RTLD_LAZY);
printf("libxml2 path: %s\n", pathname_for_handle(libxml2));
dlclose(libxml2);
return 0;
}
If you run this code, it will yield the expected result: libxml2 path: /usr/lib/libxml2.2.dylib
After about a year of using the solution provided by 0xced, we discovered an alternative method that is simpler and avoids one (rather rare) failure mode; specifically, because 0xced's code snippet iterates through each dylib currently loaded, finds the first exported symbol, attempts to resolve it in the dylib currently being sought, and returns positive if that symbol is found in that particular dylib, you can have false positives if the first exported symbol from an arbitrary library happens to be present inside of the dylib you're currently searching for.
My solution was to use _dyld_get_image_name(i) to get the absolute path of each image loaded, dlopen() that image, and compare the handle (after masking out any mode bits set by dlopen() due to usage of things like RTLD_FIRST) to ensure that this dylib is actually the same file as the handle passed into my function.
The complete function can be seen here, as a part of the Julia Language, with the relevant portion copied below:
// Iterate through all images currently in memory
for (int32_t i = _dyld_image_count(); i >= 0 ; i--) {
// dlopen() each image, check handle
const char *image_name = _dyld_get_image_name(i);
uv_lib_t *probe_lib = jl_load_dynamic_library(image_name, JL_RTLD_DEFAULT);
void *probe_handle = probe_lib->handle;
uv_dlclose(probe_lib);
// If the handle is the same as what was passed in (modulo mode bits), return this image name
if (((intptr_t)handle & (-4)) == ((intptr_t)probe_handle & (-4)))
return image_name;
}
Note that functions such as jl_load_dynamic_library() are wrappers around dlopen() that return libuv types, but the spirit of the code remains the same.

External Functions and Parameter Size Limitation (C)

I am very much stuck in the following issue. Any help is very much appreciated!
Basically I have a program wich contains an array of structs and I am getting a segmentation error when I call an external function. The error only happens when I have more than 170 items on the array being passed.
Nothing on the function is processed. The program stops exactly when accessing the function.
Is there a limit for the size of the parameters that are passed to external functions?
Main.c
struct ratingObj {
int uid;
int mid;
double rating;
};
void *FunctionLib; /* Handle to shared lib file */
void (*Function)(); /* Pointer to loaded routine */
const char *dlError; /* Pointer to error string */
int main( int argc, char * argv[]){
// ... some code ...
asprintf(&query, "select mid, rating "
"from %s "
"where uid=%d "
"order by rand()", itable, uid);
if (mysql_query(conn2, query)) {
fprintf(stderr, "%s\n", mysql_error(conn2));
exit(1);
}
res2 = mysql_store_result(conn2);
int movieCount = mysql_num_rows(res2);
// withhold is a variable that defines a percentage of the entries
// to be used for calculations (generally 20%)
int listSize = round((movieCount * ((double)withhold/100)));
struct ratingObj moviesToRate[listSize];
int mvCount = 0;
int count =0;
while ((row2 = mysql_fetch_row(res2)) != NULL){
if(count<(movieCount-listSize)){
// adds to another table
}else{
moviesToRate[mvCount].uid = uid;
moviesToRate[mvCount].mid = atoi(row2[0]);
moviesToRate[mvCount].rating = 0.0;
mvCount++;
}
count++;
}
// ... more code ...
FunctionLib = dlopen("library.so", RTLD_LAZY);
dlError = dlerror();
if( dlError ) exit(1);
Function = dlsym( FunctionLib, "getResults");
dlError = dlerror();
(*Function)( moviesToRate, listSize );
// .. more code
}
library.c
struct ratingObj {
int uid;
int mid;
double rating;
};
typedef struct ratingObj ratingObj;
void getResults(struct ratingObj *moviesToRate, int listSize);
void getResults(struct ratingObj *moviesToRate, int listSize){
// ... more code
}
You are likely blowing up the stack. Move the array to outside of the function, i.e. from auto to static land.
Another option is that the // ... more code - array gets populated... part is corrupting the stack.
Edit 0:
After you posted more code - you are using C99 variable sized array on the stack - Bad IdeaTM. Think what happens when your data set grows to thousands, or millions, of records. Switch to dynamic memory allocation, see malloc(3).
You don't show us what listsize is, but I suppose it is a variable and not a constant.
What you are using are variable length arrays, VLA. These are a bit dangerous if they are too large since they usually allocated on the stack.
To work around that you can allocate such a beast dynamically
struct ratingObj (*movies)[listSize] = malloc(sizeof(*movies));
// ...
free(movies);
You'd then have in mind though that movies then is a pointer to array, so you have to reference with one * more than before.
Another, more classical C version would be
struct ratingObj * movies = malloc(sizeof(*movies)*listsize);
// ...
free(movies);

Resources