1

I have a function named testdynamic which is called dynamically with dlopen and dlsym. Now, I have created a structure:

typedef struct BigStruct{
    char el[2000];
}BigStruct;

which is used to store the parameters for the function. Then, I allocate space to a variable named:

void *cur = (void*)malloc(totalSize);

where, totalSize is the size of the parameters. I have this information beforehand.

After that I copy all the parameters to cur.

Then, I cast it to BigStruct like this:

BigStruct *bg;
bg = (BigStruct*)cur;

And run it like this:

void* ch = (void*)testdynamic(*bg);

Now in the function testdynamic when I am printing the parameters, I am getting correct values for all data types like char**, int*, int, etc.

The only data type which is not working is char*. Even before calling the function with *bg, the contents of bg->el is correct even for char*. But, after calling, an error occurs.

What could be the problem?

Here is the code of testdynamic

char* testdynamic(char* x, char* y){
    printf("%s %s\n", x, y);
    return "hello";
}

I want to pass the parameters to the function testdynamic from my code.
This testdynamic can be any function which could accept any parameter of any type.
I get the information about the function during runtime. Since the size of char* is 1, I am casting everything to char* and then passing it to the function.
At this point, I am getting a runtime error if I am printing anything inside testdynamic which is of type char*.

Leonid Glanz
  • 1,261
  • 2
  • 16
  • 36
Rishi
  • 1,987
  • 6
  • 32
  • 49
  • 4
    More information please! – Nik Bougalis Aug 05 '13 at 17:38
  • What more information is needed? I will edit my question. – Rishi Aug 05 '13 at 17:47
  • 1
    What kind of error do you get? Have you tried running the code under the debugger? How are your "printing the parameters?" What does the declaration of `testdynamic` look like? How do you stuff arguments inside of it? Why are you passing a *COPY* of `BigStruct` on the stack to `testdynamic`? How do you "unstuff" arguments inside of `testdynamic`? What do you do with those arguments? Etc. – Nik Bougalis Aug 05 '13 at 17:56
  • 1
    You don't need casting, as all conversions to or from `void *` are automatically converted to appropriate type. – mohit Aug 05 '13 at 17:58
  • 1) Given example of failed output. 2) Since *bg is good before `testdynamic(*bg)` and bad afterward, please provide `testdynamic()` code. – chux - Reinstate Monica Aug 05 '13 at 18:00
  • Do you really need us to tell you what's wrong? You're calling a function that takes two pointers, and instead of two pointers, you're stuffing into it a 2000 byte buffer; it's like you are trying to fit a really large square peg in two small round holes at the same time. How does this even *compile*?!? – Nik Bougalis Aug 05 '13 at 18:21

6 Answers6

0

You are assuming that BigStruct looks exactly like an array of 2000 characters. This is compiler dependent and unlikely to be true. I guess you really want to copy the data pointed to by cur into the el array and not to write it all over BigStruct itself which will have some internal storage format that you cannot know.

David Elliman
  • 1,379
  • 8
  • 15
  • Since sizeof char* is 1, that why I typecast to BigStruct. Its working for all other types. – Rishi Aug 05 '13 at 17:49
  • 1
    Even if it sometimes works Rishi, this is not the way to write code that copies contents into structures. It makes too many assumptions about how the compiler stores them. It only compiles because you use void * pointers and will be prone to all manner of memory overwriting errors. – David Elliman Aug 05 '13 at 17:54
  • That it works some of the time doesn't mean it's right. Eating raw meat also works fine... except, sometimes, when you eat chicken and really bad things happen. – Nik Bougalis Aug 05 '13 at 17:59
0

So to summarise what I understand you're doing:

  • Treating cur as a char* and copying a parameter list into it
  • Casting cur as a BigStruct* and then passing it to the testdynamic function.

This seems to me like an odd way of going about this, and without looking inside the testdynamic function I would guess that this is what is causing the error. I would recommend changing your definition of BigStruct:

typedef struct {
    char * el;
} BigStruct;

And that way, you can malloc space for your char array, copy your parameter list to it, and then set the char * in the BigStruct to point to the relevant block of memory as follows:

char * cur = malloc(totalSize);
// Copy parameters over into cur
BigStruct * bg = malloc(sizeof(BigStruct));
bg->el = cur;

And then call your testdynamic function again. Try this, do you still get a runtime error?

edit: having seen the content of the testdynamic function, I can see several problems with it

char* testdynamic(char* x, char* y){
    printf("%s %s\n", x, y);
    return "hello";
}
  1. The function accepts 2 char * but you only seem to pass 1 in your code. What should it print for y if you only give it an argument for x?
  2. Let's assume you are now passing arguments for both x and y. Are you sure that both strings are null-terminated? printf works by printing characters until it finds the '\0' character.
  3. You can't just return a string literal from within a function like that. That string literal belongs to the function, and once the function returns you can't guarantee that the memory which held the string will still be safe to access again. If you want to return a string like that, you should first malloc() space for the string and return the address to the allocated block of memory.
WhoBuntu
  • 304
  • 2
  • 4
  • 1
    Your point 3 is wrong. `return "hello"` is **perfectly** valid. Returning it as a `char*` is technically wrong since a string literal is of type `const char *`, but it's not a fatal error. – Nik Bougalis Aug 05 '13 at 18:18
  • Thanks for pointing that out to me @NikBougalis, I double-checked and found [this thread](http://stackoverflow.com/questions/267114/scope-of-string-literals) which clarified it further for me. – WhoBuntu Aug 05 '13 at 18:40
  • @NikBougalis It is incorrect to say that string literals are of type `const char *`. For historical reasons, string literals do not have `const` type in C. It is still undefined behavior to modify them. – This isn't my real name Aug 05 '13 at 21:52
  • @ElchononEdelson Thanks for pointing that out; another subtle difference between C and C++ to remember. – Nik Bougalis Aug 05 '13 at 22:31
0

If totalSize > sizeof(BigStruct), you have problems for you are not passing a complete copy of your data to testdynamic(), likely messing up the copy and hence undefined behavior.

If totalSize < sizeof(BigStruct), you have problems for you are reading memory space you do not own when you pass *bg to testdynamic() - hence undefined behavior.

You are much safer simply with

bg = malloc(*bg);

There other questionable program issues going on here too, but a more complete posting would be needed.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

This only works if the size is sizeof(BigStruct)

You can't assume a structure is the size of its content, since compilers might make assumptions of alignment, etc.

If you just want 20,000 chars, then malloc it inside the BigStruct like others have suggested.

Ferrmolina
  • 2,737
  • 2
  • 30
  • 46
Tony
  • 33
  • 4
0

After reading it some more....

you're passing in one parameter for a function that requires 2 parameters.

Are you using -Wall for warning treated as errors during compilation? The second parameter isn't passed in, i.e, argument y is null. Accessing null would cause the problem.

Tony
  • 33
  • 4
0

To provide accurate, non-opinionated comments, a copy of the code is required. Thus, I have taken your comments and produced the following code. It is probably NOT what you want to do. However, a programming problem should be approached in steps or increments.

That is, get something simple to work and then make it a little more complex, but still working, and work towards your final version. This is how many of us work. No one is able to write a complex program correctly the first time, especially if new to the language!

#include <stdio.h>
#include <stdlib.h>
char *testdynamic(char *x, char* y){

        printf("%s %s\n", x, y);
        return "hello";
    }

main()
{
    typedef struct BigStruct{
        char el[2000];
    } BigStruct;

    char      *ret_char_ptr;

    BigStruct *bg;

    char x[] = "abcd";
    char y[] = "23456";

    bg = malloc(sizeof(BigStruct));

    // invoke the testdynamic function
    ret_char_ptr = testdynamic(x, y);


    printf("%s\n", ret_char_ptr);

}

I ran this code on Eclipse/Microsoft C compiler and got the following output:

abcd 23456
hello

Note. BigStruct has yet to used in this code. Not sure what your intent is, but C does provide a way to pass parameter lists that vary in length and data from several different calls to the same function.

JackCColeman
  • 3,777
  • 1
  • 15
  • 21
  • The function testdynamic is loaded dynamically.Why are you passing x, y to it? Please see what happens when you pass bg to it. – Rishi Aug 05 '13 at 19:00