I have the following code which simply loads the library test.so from the current directory and executes the version function within that library. What should be returned is a string. What is instead returned is junk from the stack(a pointer location maybe?). Does anyone have any idea why the following code would be failing.
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int main(int argc, char **argv){
void *handler;
char *(*version);
char *error;
handler = dlopen("./test.so", RTLD_LAZY);
if(!handler){
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); //Flushes any existing error
*(void **)(&version) = dlsym(handler, "version");
if((error = dlerror()) != NULL){
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("%s\n", version);
dlclose(handler);
exit(EXIT_SUCCESS);
}
Change the declaration:
char *(*version); // this is not a function pointer
to:
char *(*version)(); // but this is
then, change the line:
printf("%s\n", version);
to:
printf("%s\n", version());
dlsym just returns a function pointer. You still need to actually call it, which you can do by casting the (void*) to a function pointer of the appropriate type and calling that.
There are two errors in your code:
The declaration of version: it is a pointer to a pointer to char in your code, which led you to a weird conversion in:
*(void **)(&version) = dlsym(handler, "version");
Instead use a pointer to function returning pointer to char, like so:
char *(*version)();
and use a regular assignment:
version = dlsym(handler, "version");
You are not calling the function, when you print the result. In C, writing just the function name returns its address, so version and &version are equivalent. Your code should be like:
printf("%s\n", version());
Related
I am working in a piece of code which loads a function (that receives 2 char pointers and an int and returns an int) from a dynamic library and it´s giving me trouble. I have no access to the library code. My code looks like this:
typedef int (*func_t)(char*, char*, int);
func_t funcptr;
void *lib = dlopen(library.so, RTLD_LAZY);
if(dlerror() != NULL)
fprintf(stderr, "Error at dlopen");
funcptr = (func_t) dlsym(lib, "function");
if(dlerror() != NULL)
fprintf(stderr, "Error at dlsym");
(*funcptr)(arg1, arg2, arg3);//arguments are correct, no problem there
dlclose(lib);
When I run it, it always throws both error messages and the function doesn´t execute. I have tried almost everything. Anybody can help?
EDIT: I have printed the strings returned by dlerror(): first it says "no such file or directory", and then "undefined symbol: function". I thought I might be searching in a wrong directory, so I checked it using getcwd and I am searching in the right directory.
Read carefully dlopen(3)..
Notice that dlopen has a strange but documented behavior when given a file name without /; so read carefully that man page several times!
The library.so looks very suspicious.... Do you really have a library variable with a field named so? Maybe you want a literal string "library.so" instead. Then try
typedef int (func_sig_t)(char*, char*, int);
func_sig_t* funcptr;
void *lib = dlopen("./library.so", RTLD_LAZY);
if (!lib)
{ fprintf(stderr, "dlopen failed: %s\n", dlerror());
exit(EXIT_FAILURE); };
funcptr = (func_sig_t*) dlsym(lib, "function");
if (!funcptr)
{ fprintf(stderr, "dlsym failed: %s\n", dlerror());
exit(EXIT_FAILURE); };
int res = funcptr(arg1, arg2, arg3);
dlclose (lib);
funcptr = NULL;
Compile with gcc -Wall -g. And also use the gdb debugger!
How can I walk through all the commits of a branch using libgit2?
I have already the following bit of code, but it doesn't compile.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>
int main(int argc, char *argv[]){
git_repository *repo;
git_repository_open(&repo, ".");
git_odb *obj_db;
obj_db = git_repository_database(repo);
git_object commit;
git_revparse_single(&commit, repo, "HEAD");
git_repository_free(repo);
return 0;
}
GCC reports:
log.c: In function ‘main’:
log.c:11:9: warning: assignment makes pointer from integer without a cast [enabled by default]
log.c:13:13: error: storage size of ‘commit’ isn’t known
I compiled with the -lgit2 flag. Is there a fast possibility to walk through all the commits, beginning from the root-commit?
Update
The new code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>
int main(int argc, char *argv[]){
git_repository *repo;
git_repository_open(&repo, ".");
git_odb *obj_db;
obj_db = git_repository_database(repo);
git_object *commit;
git_revparse_single(&commit, repo, "HEAD");
git_repository_free(repo);
return 0;
}
I get the following error messages:
log.c:11: undefined reference to `git_repository_database'
log.c:14: undefined reference to `git_revparse_single'
Finally, I created a working version using libgit2. Carlos Martín Nieto pointed in the right direction, the following example works great with libgit2 0.16. It took me some time to study the general.c I found in the libgit2-examples repository on github. git revwalk was exactly what I was looking for.
I noted that git adds an newline at the end of my commit messages, probably because I'm always using nano to write them, so I don't printf out the last character in my example code.
If anyone reads this and has the same problem as I had, here's the working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <git2.h>
#define REPO ".git"
int main(void){
git_repository *repo;
if(git_repository_open(&repo, REPO) != GIT_SUCCESS){
fprintf(stderr, "Failed opening repository: '%s'\n", REPO);
return 1;
}
// Read HEAD on master
char head_filepath[512];
FILE *head_fileptr;
char head_rev[41];
strcpy(head_filepath, REPO);
if(strrchr(REPO, '/') != (REPO+strlen(REPO)))
strcat(head_filepath, "/refs/heads/master");
else
strcat(head_filepath, "refs/heads/master");
if((head_fileptr = fopen(head_filepath, "r")) == NULL){
fprintf(stderr, "Error opening '%s'\n", head_filepath);
return 1;
}
if(fread(head_rev, 40, 1, head_fileptr) != 1){
fprintf(stderr, "Error reading from '%s'\n", head_filepath);
fclose(head_fileptr);
return 1;
}
fclose(head_fileptr);
git_oid oid;
git_revwalk *walker;
git_commit *commit;
if(git_oid_fromstr(&oid, head_rev) != GIT_SUCCESS){
fprintf(stderr, "Invalid git object: '%s'\n", head_rev);
return 1;
}
git_revwalk_new(&walker, repo);
git_revwalk_sorting(walker, GIT_SORT_TOPOLOGICAL);
git_revwalk_push(walker, &oid);
const char *commit_message;
const git_signature *commit_author;
while(git_revwalk_next(&oid, walker) == GIT_SUCCESS) {
if(git_commit_lookup(&commit, repo, &oid)){
fprintf(stderr, "Failed to lookup the next object\n");
return 1;
}
commit_message = git_commit_message(commit);
commit_author = git_commit_committer(commit);
// Don't print the \n in the commit_message
printf("'%.*s' by %s <%s>\n", strlen(commit_message)-1, commit_message, commit_author->name, commit_author->email);
git_commit_free(commit);
}
git_revwalk_free(walker);
return 0;
}
Thanks!
I have already the following bit of code, but it doesn't compile
A git_commit is an opaque type, which means that your compiler doesn't know what it is, only that it exists. Thus you cannot allocate a git_commit on the stack. The library will allocate it on the heap for you.
You must use a pointer in your code and pass a pointer to that to the library's functions, as you can see in its documentation and the examples it links to.
Is there a fast possibility to walk through all the commits, beginning from the root-commit?
Those revwalk tests, demonstrating different walking strategies, may provide you with some help.
Adding to Pentax's answer above. If you just want to 'walk' the head, instead of doing all that work to get the old to the head to initialize the walker with:
git_revwalk_push(walker, &oid);
One could simply use:
git_revwalk_push_head(walker);
So, I've got a function that loads up a char** variable with some string data. My goal is to fork the process, and print some of that data in the child, and some from the parent. However, I'm unable to reference the pointer after the fork() call.
I thought that fork() made a copy of the entire address space of the parent process, which seems that it would include the various stack pointers...
Essentially, my code currently looks like this:
load_data(char **data);
char** data;
load_data(data);
printf("String 0: %s\n", data[0]);
fork();
printf("String 0 again: %s\n", data[0]); /* Segfaults Here! */
Anyone have any ideas what I'm doing wrong? I've done a bit of google searching on this, and it seems what I'm doing should work - but it doesn't. Thus, I'm misunderstanding something fundamental...
You're doing bad pointer operations and just getting lucky on the first call - here's what the code should look like:
load_data(char **data);
char* data = NULL;
load_data(&data);
printf("String 0: %s\n", data);
fork();
printf("String 0 again: %s\n", data); /* Doesn't Segfault Here! */
In your case, data doesn't point anywhere. Using an uninitialized variable is undefined behaviour. Even if it changed inside the load_data function, the change wouldn't be visible outside.
You need to either make data point to something valid, or pass the address of data to the function to have the changes "return", as in load_data(char ***data).
Your code, with minimal changes to make it a complete program, "works" for me
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int load_data(char **data);
int main(void) {
char **data;
data = malloc(2 * sizeof *data);
assert(data && "no memory");
load_data(data);
printf("String 0: %s\n", data[0]);
fork();
printf("String 0 again: %s\n", data[0]);
return 0;
}
int load_data(char **data) {
data[0] = "one";
data[1] = "two";
return 2;
}
And a sample run
$ ./a.out
String 0: one
String 0 again: one
String 0 again: one
When I define an array on the device (that is initialized with a "Hello" string in this example) and try to copy this to the host, I get the error code cudaErrorInvalidValue. However, from inside a kernel, the d_helloStr[] can be accessed. Referring to the CUDA programming guide chapter B.2.1, such a variable should also be accessible through the runtime library. Why does this example code not work?
#include <cuda.h>
#include <stdio.h>
__device__ char d_helloStr[] = {'H','e','l','l','o','\0'};
// Host function
int
main(int argc, char** argv)
{
cudaError_t err;
char h_helloStr [sizeof(d_helloStr)];
// copy device string to host string:
err = cudaMemcpy(h_helloStr, d_helloStr, sizeof(d_helloStr), cudaMemcpyDeviceToHost);
printf("err = %d\n", err);
// result string:
printf("%s\n", h_helloStr);
return 0;
}
You should use cudaMemcpyFromSymbol.
I want to invoke a shell in C program by execve:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
main()
{
char* path = "/bin/sh";
int err = execve(path, &path, NULL);
printf("%d\n", err);
printf("%s\n", strerror(errno));
printf("%x, %x\n", path, &path);
}
However the output is:
-1
Bad address
80485c0, bf816f4c
Because you aren't sending a NULL terminated list of arguments.
You need:
char* path[2];
path[0] = "/bin/sh";
path[1] = NULL;
int err = execve(path[0], path, NULL);
The second argument to execve is defined as being a NULL-terminated list of strings, so you can't simply pass the address of path. It expects an array like this, with the final entry being NULL:
arg[0] = "/bin/ls"
arg[1] = "-l"
arg[2] = "/usr/include/std*"
arg[3] = NULL
The reason it was failing with a bad pointer is that execve would have been looking at each word following path to find the arguments, and treating each word as a pointer until it got to the first 0 word. Since path was alone on the stack, it would have been trying to interpret whatever garbage happened to be in memory after the stack beyond path as a string pointer.
The solution is simple: you need to construct an array of parameters and add a NULL terminator (since it is of variable length). The fixed example is below (with a few warnings taken care of):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main()
{
char* path[] = { "/bin/sh", NULL };
int err = execve(path[0], path, NULL);
printf("%d\n", err);
printf("%s\n", strerror(errno));
printf("%p, %p\n", path, &path);
return 0;
}
Try this instead:
execl(path, path, NULL)
The exec family of functions will automatically execute a shell if the program is a script rather than a process image file. So you might be able to replace "path" with the pathname of the script.