3

I'd like to take advantage of MALLOC_PERTURB_ environment variables that can change memory allocation parameters (man 3 mallopt). However, I'd like to control allocation parameters on application level, not entire system level. Ideally, if I could control them through project's makefile. I've tried to change mentioned variables through makefile, yet, without success.

For testing, I've created this test.c file:

#include<stdlib.h>
#include<stdio.h>

#define N 50

int main()
{
    char *chars;
    int i;

    if (NULL == (chars = malloc(N * sizeof(*chars))))
        return EXIT_FAILURE;

    free(chars);

    for (i = 0; i < N; ++i)
        printf("%c", chars[i]);
    printf("\n");

    return EXIT_SUCCESS;
}

Yes, I'm aware that I am reading from freed memory, yet that's a whole point of using MALLOC_PERTURB_.

Expected result: 50 chars of ASCII character of value MALLOC_PERTURB_.

Close enough:

$ export MALLOC_PERTURB_=97
$ gcc test.c -o test
$ ./test
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa��


$ export MALLOC_PERTURB_=105
$ gcc test.c -o test
$ ./test
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii��

Then I've tried to enclose compilation in makefile, yet without success.

Exporting variable (as proposed here)

Makefile

all:
    export MALLOC_PERTURB_=110
    gcc test.c -o test

Result (I was expecting 'n' letters for 110)

$ export MALLOC_PERTURB_=105
$ make
export MALLOC_PERTURB_=110
gcc test.c -o test 
$ ./test
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii��

Calling make recursively (as proposed here)

Makefile

all:
    MALLOC_PERTURB_=110
    $(MAKE) rec

rec:
    gcc test.c -o test

Result (I was expecting 'n' letters for 110)

$ export MALLOC_PERTURB_=105
$ make
MALLOC_PERTURB_=110
make rec
make[1]: Entering directory '~/test'
gcc test.c -o test
make[1]: Leaving directory '~/test'
$ ./test
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii��

I've tried to find any inspiration from github's makefiles that included MALLOC_PERTURB_, yet they are too complex for me to understand. Some examples: (1), (2), (3)

Some technical info:

Linux 4.0.1-1-ARCH x86_64
gcc version 4.9.2 20150304 (prerelease) (GCC)
GNU Make 4.1
jww
  • 97,681
  • 90
  • 411
  • 885
browning0
  • 901
  • 2
  • 11
  • 21
  • just for my edification, what is this expression: 'sizeof(*chars)' trying to accompolish? The only thing sizeof() knows is 'char * chars' has a size of (for 32 bit systems) 4 and dereferencing the pointer is 1. This seems to be a convoluted way of saying sizeof( char), which is always 1 and never needed in a malloc() parameter – user3629249 Jun 06 '15 at 22:26
  • 1
    in the first example, the only lines relevant to your question are: '.PHONY: test test: $(BIN)/gtest$(BASENAME) MALLOC_PERTURB_=21 MALLOC_CHECK_=2 LD_LIBRARY_PATH=$(LIB) $(BIN)/gtest$(BASENAME)' where 2 (temporary) environment variables are being set before calling the gtest... program – user3629249 Jun 06 '15 at 22:37
  • You can add a semicolon and a backslash after your `export` line and it will work. As it stands, `make` creates a shell that runs the `export`, and then creates another shell to run the test (so the second shell has no clue about the exported variable). What I suggest forces `make` to treat the two lines as one. There's also an directive that you can add to a `makefile` that tells GNU `make` to run all the actions for a target in a single shell; it is appropriately named `.ONESHELL:`. – Jonathan Leffler Jun 07 '15 at 02:53
  • @user3629249 Considering sizeof: I prefer using sizeof(*VARIABLE_NAME) than sizeof(VARIABLE_TYPE) as it allows me to quickly and safely change variable type. That way I don't have to search for all occurences of sizeof(VARIABLE_TYPE) in my code. See the accepted answer of this question: (http://stackoverflow.com/questions/373252/c-sizeof-with-a-type-or-variable) for more info. – browning0 Jun 07 '15 at 09:53
  • Possible duplicate of [Setting environment variable in Makefile](https://stackoverflow.com/q/8022586/608639) – jww Jun 07 '18 at 23:19

3 Answers3

5

In Bash, you can specify environment variables in front of the command, e.g.,

MALLOC_PERTURB_=105 gcc test.c -o test

or

MALLOC_PERTURB_=105 ./test

(I believe only the run has to have this variable set, not the compile.)

Since you are on Linux there is a good chance Make will use Bash as shell and you can put the line above in your makefile.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Atafar
  • 697
  • 7
  • 10
2

Browning, setting an environment variable in the makefile is easy, and you have done so, but that is not what you want. That makes it take that value during the compile. But you want it to change malloc's behavior when you run the program.

Reading the man page you referenced confirms that you need to set the environment variable in the environment where your program is running. Also reading the comments, it is already mentioned that the makefiles that set the environment variable only do so for a test program, which they actually run as part of the build.

You do not want it in the makefile. You want it set while you actually run the program, which is what the other comments and answers are telling you how to do. Sorry for taking up an answer, but I needed more room to clear that up, plus it is the answer, for you. You already know how to do it. You just didn't know what it was, exactly.

Kenny Ostrom
  • 5,639
  • 2
  • 21
  • 30
2

You can set the "MALLOC_PERTURB_" value at compile time as well by passing the M_PERTURB option to the mallopt() function (glibc 2.4 or later). See http://man7.org/linux/man-pages/man3/mallopt.3.html for details.

So if you want your program to incorporate the setting of the environment variable "MALLOC_PERTURB_" at compile time, then something like this should work:

#include<stdlib.h>
#include<stdio.h>

#include <malloc.h> // for mallopt() and M_PERTURB

#define N 50

int main()
{
    char *chars;
    int i;

#if MALLOC_PERTURB_
    mallopt( M_PERTURB, MALLOC_PERTURB_);
#endif

    if (NULL == (chars = malloc(N * sizeof(*chars))))
        return EXIT_FAILURE;

    free(chars);

    for (i = 0; i < N; ++i)
        printf("%c", chars[i]);
    printf("\n");

    return EXIT_SUCCESS;
}

Then have your makefile pass the MALLOC_PERTURB_ value as a macro definition on the compiler command line (or whatever mechanism you want to use):

gcc -DMALLOC_PERTURB_=97 test.c -o test
Michael Burr
  • 333,147
  • 50
  • 533
  • 760