tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

meminfo.c (3954B)


      1 /* Copyright (c) 2003-2004, Roger Dingledine
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file meminfo.c
      8 *
      9 * \brief Functions to query total memory, and access meta-information about
     10 * the allocator.
     11 **/
     12 
     13 #include "lib/meminfo/meminfo.h"
     14 
     15 #include "lib/cc/compat_compiler.h"
     16 #include "lib/cc/torint.h"
     17 #include "lib/fs/files.h"
     18 #include "lib/log/log.h"
     19 #include "lib/malloc/malloc.h"
     20 #include "lib/string/util_string.h"
     21 
     22 #ifdef HAVE_FCNTL_H
     23 #include <fcntl.h>
     24 #endif
     25 #ifdef HAVE_MALLOC_H
     26 #include <malloc.h>
     27 #endif
     28 #ifdef HAVE_UNISTD_H
     29 #include <unistd.h>
     30 #endif
     31 
     32 #ifdef _WIN32
     33 #include <windows.h>
     34 #endif
     35 #include <string.h>
     36 
     37 #if defined(HAVE_SYS_SYSCTL_H) && !defined(_WIN32) && !defined(__linux__)
     38 #include <sys/sysctl.h>
     39 #endif
     40 
     41 #if defined(HW_PHYSMEM64)
     42 /* OpenBSD and NetBSD define this */
     43 #define INT64_HW_MEM HW_PHYSMEM64
     44 #elif defined(HW_MEMSIZE)
     45 /* OSX defines this one */
     46 #define INT64_HW_MEM HW_MEMSIZE
     47 #endif /* defined(HW_PHYSMEM64) || ... */
     48 
     49 /**
     50 * Helper: try to detect the total system memory, and return it. On failure,
     51 * return 0.
     52 */
     53 static uint64_t
     54 get_total_system_memory_impl(void)
     55 {
     56 #if defined(__linux__)
     57  /* On linux, sysctl is deprecated. Because proc is so awesome that you
     58   * shouldn't _want_ to write portable code, I guess? */
     59  unsigned long long result=0;
     60  int fd = -1;
     61  char *s = NULL;
     62  const char *cp;
     63  size_t file_size=0;
     64  if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
     65    return 0;
     66  s = read_file_to_str_until_eof(fd, 65536, &file_size);
     67  if (!s)
     68    goto err;
     69  cp = find_str_at_start_of_line(s, "MemTotal:");
     70  if (!cp)
     71    goto err;
     72  /* Use the system sscanf so that space will match a wider number of space */
     73  if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1)
     74    goto err;
     75 
     76  close(fd);
     77  tor_free(s);
     78  return result * 1024;
     79 
     80  /* LCOV_EXCL_START Can't reach this unless proc is broken. */
     81 err:
     82  tor_free(s);
     83  close(fd);
     84  return 0;
     85  /* LCOV_EXCL_STOP */
     86 #elif defined (_WIN32)
     87  /* Windows has MEMORYSTATUSEX; pretty straightforward. */
     88  MEMORYSTATUSEX ms;
     89  memset(&ms, 0, sizeof(ms));
     90  ms.dwLength = sizeof(ms);
     91  if (! GlobalMemoryStatusEx(&ms))
     92    return 0;
     93 
     94  return ms.ullTotalPhys;
     95 
     96 #elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM)
     97  /* On many systems, HW_PHYSMEM is clipped to 32 bits; let's use a better
     98   * variant if we know about it. */
     99  uint64_t memsize = 0;
    100  size_t len = sizeof(memsize);
    101  int mib[2] = {CTL_HW, INT64_HW_MEM};
    102  if (sysctl(mib,2,&memsize,&len,NULL,0))
    103    return 0;
    104 
    105  return memsize;
    106 
    107 #elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
    108  /* On some systems (like FreeBSD I hope) you can use a size_t with
    109   * HW_PHYSMEM. */
    110  size_t memsize=0;
    111  size_t len = sizeof(memsize);
    112  int mib[2] = {CTL_HW, HW_PHYSMEM};
    113  if (sysctl(mib,2,&memsize,&len,NULL,0))
    114    return 0;
    115 
    116  return memsize;
    117 
    118 #else
    119  /* I have no clue. */
    120  return 0;
    121 #endif /* defined(__linux__) || ... */
    122 }
    123 
    124 /**
    125 * Try to find out how much physical memory the system has. On success,
    126 * return 0 and set *<b>mem_out</b> to that value. On failure, return -1.
    127 */
    128 MOCK_IMPL(int,
    129 get_total_system_memory, (size_t *mem_out))
    130 {
    131  static size_t mem_cached=0;
    132  uint64_t m = get_total_system_memory_impl();
    133  if (0 == m) {
    134    /* LCOV_EXCL_START -- can't make this happen without mocking. */
    135    /* We couldn't find our memory total */
    136    if (0 == mem_cached) {
    137      /* We have no cached value either */
    138      *mem_out = 0;
    139      return -1;
    140    }
    141 
    142    *mem_out = mem_cached;
    143    return 0;
    144    /* LCOV_EXCL_STOP */
    145  }
    146 
    147 #if SIZE_MAX != UINT64_MAX
    148  if (m > SIZE_MAX) {
    149    /* I think this could happen if we're a 32-bit Tor running on a 64-bit
    150     * system: we could have more system memory than would fit in a
    151     * size_t. */
    152    m = SIZE_MAX;
    153  }
    154 #endif /* SIZE_MAX != UINT64_MAX */
    155 
    156  *mem_out = mem_cached = (size_t) m;
    157 
    158  return 0;
    159 }