about summary refs log tree commit diff homepage
path: root/lib/Support/MemoryUsage.cpp
blob: 5878939e4d149aefff499aa25d8cb19f2aa94a9b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//===-- MemoryUsage.cpp ---------------------------------------------------===//
//
//                     The KLEE Symbolic Virtual Machine
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "klee/System/MemoryUsage.h"

#include "klee/Config/config.h"
#include "klee/Support/ErrorHandling.h"

#ifdef HAVE_GPERFTOOLS_MALLOC_EXTENSION_H
#include "gperftools/malloc_extension.h"
#endif

#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
#include <malloc.h>
#endif
#ifdef HAVE_MALLOC_ZONE_STATISTICS
#include <malloc/malloc.h>
#endif

// ASan Support
//
// When building with ASan the `mallinfo()` function is intercepted and always
// reports zero so we can't use that to report KLEE's memory usage. Instead we
// will use ASan's public interface to query how much memory has been
// allocated.
//
// Unfortunately the interface is dependent on the compiler version. It is also
// unfortunate that the way to detect compilation with ASan differs between
// compilers. The preprocessor code below tries to determine if ASan is enabled
// and if so which interface should be used.
//
// If ASan is enabled the `KLEE_ASAN_BUILD` macro will be defined other it will
// be undefined. If `KLEE_ASAN_BUILD` is defined then the
// `ASAN_GET_ALLOCATED_MEM_FUNCTION` macro will defined to the name of the ASan
// function that can be called to get memory allocation

// Make sure we start with the macro being undefined.
#undef KLEE_ASAN_BUILD

// Clang and ASan
#if defined(__has_feature)
#  if __has_feature(address_sanitizer)
#     if __has_include("sanitizer/allocator_interface.h")
#       include <sanitizer/allocator_interface.h>
        // Modern interface
#       define ASAN_GET_ALLOCATED_MEM_FUNCTION __sanitizer_get_current_allocated_bytes
#     else
#       include <sanitizer/asan_interface.h>
        // Deprecated interface.
#       define ASAN_GET_ALLOCATED_MEM_FUNCTION __asan_get_current_allocated_bytes
#     endif /* has_include("sanitizer/allocator_interface.h") */
#    define KLEE_ASAN_BUILD
#  endif /* __has_feature(address_sanitizer) */
#endif /* defined(__has_feature) */

// For GCC and ASan
#ifndef KLEE_ASAN_BUILD
#  if defined(__SANITIZE_ADDRESS__)
     // HACK: GCC doesn't ship `allocator_interface.h`  or `asan_interface.h` so
     // just provide the proto-types here.
     extern "C" {
       size_t __sanitizer_get_current_allocated_bytes();
       size_t __asan_get_current_allocated_bytes(); // Deprecated.
     }
     // HACK: Guess which function to use based on GCC version
#    if __GNUC__ > 4
       // Tested with gcc 5.2, 5.4, and 6.2.1
       // Modern interface
#      define ASAN_GET_ALLOCATED_MEM_FUNCTION __sanitizer_get_current_allocated_bytes
#    else
       // Tested with gcc 4.8 and 4.9
       // Deprecated interface
#      define ASAN_GET_ALLOCATED_MEM_FUNCTION __asan_get_current_allocated_bytes
#    endif
#    define KLEE_ASAN_BUILD
#  endif /* defined(__SANITIZE_ADDRESS__) */
#endif /* ndef KLEE_ASAN_BUILD */

using namespace klee;

size_t util::GetTotalMallocUsage() {
#ifdef KLEE_ASAN_BUILD
  // When building with ASan on Linux `mallinfo()` just returns 0 so use ASan runtime
  // function instead to get used memory.
  return ASAN_GET_ALLOCATED_MEM_FUNCTION();
#endif

#ifdef HAVE_GPERFTOOLS_MALLOC_EXTENSION_H
  size_t value = 0;
  MallocExtension::instance()->GetNumericProperty(
      "generic.current_allocated_bytes", &value);
  return value;
#elif defined(HAVE_MALLINFO2)
  // niy in tcmalloc
  struct mallinfo2 mi = ::mallinfo2();
  return mi.uordblks + mi.hblkhd;
#elif defined(HAVE_MALLINFO)
  struct mallinfo mi = ::mallinfo();
  // The malloc implementation in glibc (pmalloc2)
  // does not include mmap()'ed memory in mi.uordblks
  // but other implementations (e.g. tcmalloc) do.
#if defined(__GLIBC__)
  return (size_t)(unsigned)mi.uordblks + (unsigned)mi.hblkhd;
#else
  return (unsigned)mi.uordblks;
#endif

#elif defined(HAVE_MALLOC_ZONE_STATISTICS)

  // Memory usage on macOS

  malloc_statistics_t stats;
  malloc_zone_t **zones;
  unsigned int num_zones;

  if (malloc_get_all_zones(0, nullptr, (vm_address_t **)&zones, &num_zones) !=
      KERN_SUCCESS)
    klee_error("malloc_get_all_zones failed.");

  size_t total = 0;
  for (unsigned i = 0; i < num_zones; i++) {
    malloc_zone_statistics(zones[i], &stats);
    total += stats.size_in_use;
  }
  return total;

#else // HAVE_MALLINFO

#warning Cannot get malloc info on this platform
  return 0;

#endif
}