1

Context: How to make Valgrind log all allocations?
https://valgrind.org/docs/manual/ms-manual.html

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

enum { NBOOK = 10};
typedef struct{
    char *title;
    int pages;
} book;

typedef struct{
    int num_books,max_books;
    book *array;
} stack;

stack* create_stack();
book *add_book(stack **s,char *title,int pages);
void prn_stack(stack *s);
void free_stack(stack *s);

int main(void){
    stack *s1 = NULL; /* initialize pointers */

    add_book(&s1,"Huck Finn", 631);
    add_book(&s1,"Tom sawyer", 582);
    add_book(&s1,"The qucik brown fox", 1);

    prn_stack(s1);
    free_stack(s1);

    return 0;
}

stack* create_stack()
{
    stack *s = calloc(1,sizeof *s);

    if(!s){
        fprintf(stderr,"error: virtual memory exhausted.--stack\n");
        exit(EXIT_FAILURE);
    }
    
    s->array = calloc(NBOOK,sizeof *(s->array));
    if(!s->array){
        fprintf(stderr,"error: virtual memory exhausted.--array \n");
        exit(EXIT_FAILURE);
    }

    s->num_books = 0;
    s->max_books = NBOOK;
    return s;
}

/** since add_book may create the stack, you must pass the address
 *  of the stack to add_book so that any changes to s are available
 *  back in the calling funciton.
 */
book *add_book(stack **s,char *title,int pages)
{
    if(!title) return NULL;

    if(!*s) *s = create_stack();

    /* check num_books against max_books and realloc as required */
    if((*s)->num_books == (*s)->max_books){
        void *tmp = realloc((*s)->array,((*s)->max_books + NBOOK) * sizeof *((*s)->array));
        if(!tmp){
            fprintf(stderr, "error: memory exhausted - realloc array.\n");
            return NULL;
        }

        (*s)->array = tmp;
        (*s)->max_books += NBOOK;
    }

    /*  allocate/copy title, assign pages, increment num_books  */
    (*s)->array[(*s)->num_books].title = strdup(title);
    (*s)->array[(*s)->num_books].pages = pages;
    ((*s) ->num_books) ++;

    return &((*s)->array[(*s)->num_books - 1]);
}


void prn_stack(stack *s)
{
    if(!s) return;
    
    printf("There are %d books in the stack. maxbook is %d:\n",s->num_books,s->max_books);

    for(int i = 0; i < s->num_books ; i++)
        printf("\t%2d.\t%-20s\t(%3d pages)\n", i,s->array[i].title,s->array[i].pages);

    putchar('\n');
}

void free_stack(stack *s)
{
    if(!s) return;

    for(int i = 0; i < s->num_books; i++)
        free(s->array[i].title);
    free(s->array);
    free(s);
}

gcc -Wformat=2 -Werror=return-type array_struct35.c &&./a.out
valgrind ./a.out

return

-- total heap usage: 6 allocs, 6 frees, 1,241 bytes allocated

valgrind --tool=massif ./a.out
ms_print massif.out.69359

return

94.59% (1,241B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc.
->78.05% (1,024B) 0x48E0C23: _IO_file_doallocate (filedoalloc.c:101)
| ->78.05% (1,024B) 0x48EFD5F: _IO_doallocbuf (genops.c:347)
|   ->78.05% (1,024B) 0x48EEFDF: _IO_file_overflow@@GLIBC_2.2.5 (fileops.c:744)
|     ->78.05% (1,024B) 0x48ED754: _IO_new_file_xsputn (fileops.c:1243)
|       ->78.05% (1,024B) 0x48ED754: _IO_file_xsputn@@GLIBC_2.2.5 (fileops.c:1196)
|         ->78.05% (1,024B) 0x48D71CC: outstring_func (vfprintf-internal.c:239)
|           ->78.05% (1,024B) 0x48D71CC: __vfprintf_internal (vfprintf-internal.c:1263)
|             ->78.05% (1,024B) 0x48C281E: printf (printf.c:33)
|               ->78.05% (1,024B) 0x10955F: prn_stack (in /home/jian/helloc/a.out)
|                 ->78.05% (1,024B) 0x1092C8: main (in /home/jian/helloc/a.out)
|
->12.20% (160B) 0x109351: create_stack (in /home/jian/helloc/a.out)
| ->12.20% (160B) 0x1093F0: add_book (in /home/jian/helloc/a.out)
|   ->12.20% (160B) 0x109286: main (in /home/jian/helloc/a.out)
|
->03.12% (41B) 0x490A60E: strdup (strdup.c:42)
| ->03.12% (41B) 0x1094C6: add_book (in /home/jian/helloc/a.out)
|   ->01.60% (21B) in 2 places, all below massif's threshold (1.00%)
|   |
|   ->01.52% (20B) 0x1092BC: main (in /home/jian/helloc/a.out)
|
->01.22% (16B) 0x10930A: create_stack (in /home/jian/helloc/a.out)
  ->01.22% (16B) 0x1093F0: add_book (in /home/jian/helloc/a.out)
    ->01.22% (16B) 0x109286: main (in /home/jian/helloc/a.out)

6 allocated roughly means 6 memory related function call. So far I can only count 5. 5 == 3 strdup() function calls plus 2 calloc) function calls.


update
From https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html I know that strdup function related to memory allocation.

But printf reference https://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html I cannot found memory allocation related info.


I found out this greate question. Does fprintf use malloc() under the hood?

Rachid K.
  • 4,490
  • 3
  • 11
  • 30
jian
  • 4,119
  • 1
  • 17
  • 32
  • 6
    `printf` is allocating memory too. The log is showing it. – Eugene Sh. Sep 09 '22 at 15:37
  • 2
    The C and POSIX standards don't define anything about how standard library functions may or may not allocate memory. You will not find in any spec things like "`printf` will call malloc three times" or "printf will allocate 24 bytes". It's an implementation detail, and in general is not supposed to be any concern of the programmer. The solution here is to read the backtrace to see which allocations were performed by library functions and disregard them if appropriate. On some systems valgrind will automatically suppress them from its output. – Nate Eldredge Sep 09 '22 at 22:27
  • 1
    Prior to valgrind `3.13`, valgrind used to mask (exclude) all memory allocated by system library calls (e.g. stdio, etc..). Something changed (broke) in 3.13 and the exclusion files valgrind uses no longer mask these allocations. (which makes valgrind much less useful as a teaching tool -- without this more in-depth discussion). I wrote several bugs against this problem when it occurred and the valgrind folks basically said WONTFIX. – David C. Rankin Sep 10 '22 at 07:59

1 Answers1

1

Valgrind will normally free memory that standard libraries allocate (depending on the platform somewhat). It does this by intercepting exit() and calling the libc freeres function in libc (if it finds it).

You can turn this off with

   --run-libc-freeres=<yes|no> [default: yes]

to see these allocations (with memcheck).

Paul Floyd
  • 5,530
  • 5
  • 29
  • 43