1

I have yet again a question about the workings of C. (ANSI-C compiled by VS2012)

I am refactoring a standalone program (.exe) into a .dll. This works fine so far but I stumble accross problems when it comes to logging. Let me explain:

The original program - while running - wrote a log-file and printed information to the screen. Since my dll is going to run on a webserver, accessed by many people simultaneously there is

  • no real chance to handle log-files properly (and clean up after them)
  • no console-window anyone would see

So my goal is to write everything that would be put in the log-file or on the screen into string-like variables (I know that there are no strings in C) which I then can later pass on requet to the caller (also a dll, but written in C#).

Since in C such a thing is not possible:

char z88rlog;
z88rlog="First log-entry\n";
z88rlog+="Second log-entry\n";

I have two possibilities:

  1. char z88rlog[REALLY_HUGE];
  2. dynamically allocating memory

In my mind the first way is to be ignored because:

  • The potential waste of memory is rather enormous
  • I still may need more memory than REALLY_HUGE, thus creating a buffer overflow

which leaves me with the second way. I have done some work on that and came up with two solutions, either of which doesn't work properly.

/* Solution 1 */    
void logpr(char* tmpstr)
{
    extern char *z88rlog;
    if (z88rlog==NULL)
    {
        z88rlog=malloc(strlen(tmpstr)+1);
        strcpy(z88rlog,tmpstr);
    }
    else
    {
        z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr));
        z88rlog=strcat(z88rlog,tmpstr);
    }
}

In solution 1 (equal to solution 2 you will find) I pass my new log-entry through char tmpstr[255];. My "log-file" z88rlog is declared globally, so I need extern to access it. I then check if memory has been allocated for z88rlog. If no I allocate memory the size of my log-entry (+1 for my \0) and copy the contents of tmpstr into z88rlog. If yes I realloc memory for z88rlog in the size of what it has been + the length of tmpstr (+1). Then the two "string" are joined, using strcat. Using breakpoints an the direct-window I obtainded the following output:

z88rlog
0x00000000 <Schlechtes Ptr>
z88rlog
0x0059ef80 "start Z88R version 14OS"
z88rlog
0x0059ef80 "start Z88R version 14OS
opening file Z88.DYNÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þîþîþîþ"

It shows three consecutive calls of logpr (breakpoint before strcpy/strcat). The indistinguable gibberish at the end results from memory allocation. After that VS gives out an error message that something caused the debugger to set a breakpoint in realloc.c. Because this obviously doesn't work I concocted my wonderful solution 2:

/* Solution 2 */
void logpr(char* tmpstr)
{
    extern char *z88rlog;
    char *z88rlogtmp;
    if (z88rlog==NULL)
    {
        z88rlog=malloc(strlen(tmpstr)+1);
        strcpy(z88rlog,tmpstr);
    }
    else
    {
        z88rlogtmp=malloc(strlen(z88rlog)+strlen(tmpstr+1));
        z88rlogtmp=strcat(z88rlog,tmpstr);
        free(z88rlog);
        z88rlog=malloc(strlen(z88rlogtmp)+1);
        memcpy(z88rlog,z88rlogtmp,strlen(z88rlogtmp)+1);
        free(z88rlogtmp);
    }
}

Here my aim is to create a copy of my log-file, free the originals' memory create new memory for the original in the new size and copy the contents back. And don't forget to free the temporary copy since it's allocated via malloc. This crashes instantly when it reaches free, again telling me that the heap might be broken.

So lets comment free for the time being. This does work better - much to my relief - but while building the log-string suddenly not all characters from z88rlogtmp get copied. But everything still works kind of properly. Until suddenly I am told again that the heap might be broken and the debugger puts a breakpoint at the end of _heap_alloc (size_t size) in malloc.c size has - according to the debugger - the value of 1041.

So I have 2 (or 3) ways I want to achieve this "string-growing" but none works. Might the error giving me the size point me to the conclusion that the array has become to big? I hope I explained well what I want to do and someone can help me :-) Thanks in advance!

irony on Maybee I should just go and buy some new heap for the computer. Does it fit in RAM-slots? Can anyone recomend a good brand? irony off

3 Answers 3

2

This is one mistake in Solution 1:

z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr));

as no space is allocated for the terminating null character. Note that you must store the result of realloc() to a temporary variable to avoid memory leak in the event of failure. To correct:

char* tmp = realloc(z88rlog, strlen(z88rlog) + strlen(tmpstr) + 1);
if (tmp)
{
    z88rlog = tmp;
    /* ... */
}

Mistakes in Solution 2:

z88rlogtmp=malloc(strlen(z88rlog)+strlen(tmpstr+1));
                                      /*^^^^^^^^^*/

it is calulating one less than the length of tmpstr. To correct:

z88rlogtmp=malloc(strlen(z88rlog) + strlen(tmpstr) + 1);

Pointer reassignment resulting in undefined behaviour:

    z88rlogtmp=strcat(z88rlog,tmpstr);
    /* Now, 'z88rlogtmp' and 'z88rlog' point to the same memory. */

    free(z88rlog);
    /* 'z88rlogtmp' now points to deallocated memory. */

    z88rlog=malloc(strlen(z88rlogtmp)+1);
    /* This call   ^^^^^^^^^^^^^^^^^^ is undefined behaviour,
       and from this point on anything can happen. */

    memcpy(z88rlog,z88rlogtmp,strlen(z88rlogtmp)+1);
    free(z88rlogtmp);

Additionally, if the code is executing within a Web Server it is almost certainly operating in a multi-threaded environment. As you have a global variable it will need synchronized access.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for that answer! What do you mean by synchronized access? My variable is defined globally inside my C-DLL.
@lhiapgpeonk, if multiple threads attempt to modify z88rlog then you have a race condition. Access to z88rlog must be sycnronized, meaning only thread can access modify it at anyone time.
That sounds like I can P/Invoke to my dll from anywhere and my dll holds just one set of variables. That is rather horrible! If only I could create a kind of object from the dll in C#. Can you point me to some Explanation on how to achieve this Synchronisation?
1

You seem to have many problems. To start with in your realloc call you don't allocate space for the terminating '\0' character. In your second solution you have strlen(tmpstr+1) which isn't correct. In your second solution you also use strcat to append to the existing buffer z88rlog, and if it's not big enough you overwrite unallocated memory, or over data allocated for something else. The first argument to strcat is the destination, and that is what is returned by the function as well so you loose the newly allocated memory too.

The first solution, with realloc, should work fine, if you just remember to allocate that extra character.

2 Comments

Wonderful! Fixing my realloc did the trick! Fixing strlen(tmpstr+1) however didn't. Are the two solutions so different?
@lhiapgpeonk Yes, the two solutions are not the same, as I've noted in my updated answer.
1

In solution 1, you would need to allocate space for terminating NULL character. Hence, the realloc should include one more space i.e.

z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr) + 1);

In second solution, I am not sure of this z88rlogtmp=strcat(z88rlog,tmpstr); because z88rlog is the destination string. In case you wish to perform malloc only, then

 z88rlogtmp=malloc(strlen(z88rlog)+1 // Allocate a temporary string
 strcpy(z88rlogtmp,z88rlog); // Make a copy
 free(z88rlog); // Free current string
 z88rlog=malloc(strlen(z88rlogtmp)+ strlen(tmpstr) + 1)); //Re-allocate memory
 strcpy(z88rlog, z88rlogtmp); // Copy first string
 strcat(z88rlog, tmpStr);  // Concatenate the next string
 free(z88rlogtmp); // Free the Temporary string

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.