Thành Phạm
Thành Phạm

Reputation: 55

Interposition at compile time does not work

I am learning about interposition. The code below is taken from a course (CMU 15-213), however, when I compile, this warning "mymalloc.c:6:29: warning: all paths through this function will call itself [-Winfinite-recursion]" occurs.

As I understand, a call to malloc in main() will instead be transferred to the call to mymalloc(). Inside mymalloc(), malloc is called again and hence, the loop occurs.

//int.c

#include <stdio.h>
#include "malloc.h"

int main() {
    int *p = malloc(32);
    free(p);
    return (0);
}
//malloc.h

#include <stdlib.h>
#define malloc(size) mymalloc(size)
#define free(ptr) myfree(ptr)

void *mymalloc(size_t size);
void myfree(void *ptr);
//mymalloc.c

#ifdef COMPILETIME
#include <stdio.h>
#include "malloc.h"

/* malloc wrapper function */
void *mymalloc(size_t size) {
    void *ptr = malloc(size);
    printf("malloc(%d)=%p\n",
           (int)size, ptr);
    return ptr;
}

/* free wrapper function */
void myfree(void *ptr)
{
    free(ptr);
    printf("free(%p)\n", ptr);
}
#endif
//Makefile

CC = gcc
CFLAGS = -Wall

intc: int.c mymalloc.c
    $(CC) $(CFLAGS) -DCOMPILETIME -c mymalloc.c
    $(CC) $(CFLAGS) -I. -o intc int.c mymalloc.o

runc:
    ./intc

clean:
    rm -f *~ intr intl intc *.so *.o

I tried searching but couldn't find any solution to this problem. Can anyone please help ? Thank you.

Upvotes: 5

Views: 104

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 222933

The #define malloc(size) mymalloc(size) in malloc.h results in the code void *ptr = malloc(size); in mymalloc.c being changed to void *ptr = mymalloc(size);.

Solutions include:

  • Change void *ptr = malloc(size); to void *ptr = (malloc)(size);. Then, because malloc is not followed by a parentheses, the function-like macro will have no effect. Also change free(ptr); to (free)(ptr);.
  • Insert #undef malloc after #include "malloc.h" in mymalloc.c.
  • Make a file called privatemalloc.h that declares the routines and change malloc.h to have #include "privatemalloc.h" instead of declaring the routines directly. Then use #include "privatemalloc.h" in mymalloc.c instead of #include "malloc.h". Continue using #include "malloc.h" in other source files. So other source files will get the macro definitions, but mymalloc.c will not.
  • Change malloc.h to define the macros only if some symbol, say PrivateMalloc, is not defined. In mymalloc.c, insert #define PrivateMalloc 1 before #include "malloc.h".
  • Insert #define mymalloc malloc after #include "malloc.h" in mymalloc.c. When malloc is later replaced by mymalloc, this #define will cause mymalloc to be replaced by malloc. Macro replacement will then stop, as recursive macro replacements are not performed. Similarly, the mymalloc in the source code will be replaced by malloc and then mymalloc.

Upvotes: 1

J_H
J_H

Reputation: 20460

You wrote

#include "malloc.h"
...
void *mymalloc(size_t size) {
    void *ptr = malloc(size);

which after preprocessing comes out as

void *mymalloc(size_t size) {
    void *ptr = mymalloc(size);

The diagnostic is accurate. Infinite recursion won't make you happy, as it will lead to stack overflow.

The #define malloc(size) mymalloc(size) is good for user application code, but not for the library code you're writing here. Arrange for application and library source files to consume appropriate macro definitions. You might need one more header file, here.

You wrote that both int.c and mymalloc.c should #include "malloc.h". No, that cannot be. The int.c application can consume a #define which changes what "malloc()" means. But the mymalloc.c library code cannot, as it must access the original libc malloc routine.

Upvotes: 4

Related Questions