allocator

替换CRT堆处理函数

base/allocator 中有个python文件用于处理VS中libcmt.lib静态库中堆的处理函数,将其obj文件去除,这对于我来说是一个比较新颖的思路,一直以为只有hook才是一个方案,没想到这种静态链接的方法也是不错的。

import os
import shutil
import subprocess
import sys

def run(command, env_dict):
  """Run |command|.  If any lines that match an error condition then
      terminate.

  The env_dict, will be used for the environment. None can be used to get the
  default environment."""
  error = 'cannot find member object'
  # Need shell=True to search the path in env_dict for the executable.
  popen = subprocess.Popen(
      command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True,
      env=env_dict)
  out, _ = popen.communicate()
  for line in out.splitlines():
    print line
    if error and line.find(error) != -1:
      print 'prep_libc.py: Error stripping object from C runtime.'
      sys.exit(1)

def main():
  bindir = 'SELF_X86'
  objdir = 'INTEL'
  vs_install_dir = sys.argv[1]
  outdir = sys.argv[2]
  if "x64" in sys.argv[3]:
    bindir = 'SELF_64_amd64'
    objdir = 'amd64'
    vs_install_dir = os.path.join(vs_install_dir, 'amd64')

  if len(sys.argv) == 5:
    env_pairs = open(sys.argv[4]).read()[:-2].split('\0')
    env_dict = dict([item.split('=', 1) for item in env_pairs])
  else:
    env_dict = None  # Use the default environment.

  output_lib = os.path.join(outdir, 'libcmt.lib')
  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib)
  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'),
                  os.path.join(outdir, 'libcmt.pdb'))
  cvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
      '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativec\\\\';
  cppvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
      '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativecpp\\\\';

  cobjfiles = ['malloc', 'free', 'realloc', 'heapinit', 'calloc', 'recalloc',
      'calloc_impl']
  cppobjfiles = ['new', 'new2', 'delete', 'delete2', 'new_mode', 'newopnt',
      'newaopnt']
  for obj in cobjfiles:
    cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
           (cvspath, obj, output_lib))
    run(cmd, env_dict)
  for obj in cppobjfiles:
    cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
           (cppvspath, obj, output_lib))
    run(cmd, env_dict)

if __name__ == "__main__":
  sys.exit(main())

这是python语言,核心语句是要执行下面这个命令:

cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
           (cvspath, obj, output_lib))

主要的方式就是移除堆管理的obj数据。这里不深挖具体怎么处理,因为目前暂时遇不到这种情况,只是作为一个了解。

堆的管理

那么chromium接管了系统的heap处理后,他是要干什么呢,进行了那些优化呢,chromium如下这样注释,似乎表明了它的用意。

// Heap functions are stripped from libcmt.lib using the prep_libc.py
// for each object file stripped, we re-implement them here to allow us to
// perform additional checks:
// 1. Enforcing the maximum size that can be allocated to 2Gb.
// 2. Calling new_handler if malloc fails.

其实接管系统的heap处理,如果在Linux平台下是可以直接使用tcmalloc来接替内存申请,然而在window平台还是接着使用默认系统堆内存。

我们来看看它是如何接管内存处理的,先看堆的初始化

int _heap_init() {
  base::allocator::g_is_win_shim_layer_initialized = true;
  return win_heap_init() ? 1 : 0;
}

// VS2013 crt uses the process heap as its heap, so we do the same here.
// See heapinit.c in VS CRT sources.
bool win_heap_init() {
  // Set the _crtheap global here.  THis allows us to offload most of the
  // memory management to the CRT, except the functions we need to shim.
  _crtheap = GetProcessHeap();
  if (_crtheap == NULL)
    return false;

  ULONG enable_lfh = 2;
  // NOTE: Setting LFH may fail.  Vista already has it enabled.
  //       And under the debugger, it won't use LFH.  So we
  //       ignore any errors.
  HeapSetInformation(_crtheap, HeapCompatibilityInformation, &enable_lfh,
                     sizeof(enable_lfh));

  return true;
}

这里默认设置LFH堆属性,使用进程堆,那么堆又是如何申请的呢

// Call the new handler, if one has been set.
// Returns true on successfully calling the handler, false otherwise.
inline bool call_new_handler(bool nothrow, size_t size) {
  // Get the current new handler.
  _PNH nh = _query_new_handler();
#if defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
  if (!nh)
    return false;
  // Since exceptions are disabled, we don't really know if new_handler
  // failed.  Assume it will abort if it fails.
  return nh(size);
#else
#error "Exceptions in allocator shim are not supported!"
#endif  // defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
  return false;
}

// Implement a C++ style allocation, which always calls the new_handler
// on failure.
inline void* generic_cpp_alloc(size_t size, bool nothrow) {
  void* ptr;
  for (;;) {
    ptr = malloc(size);
    if (ptr)
      return ptr;
    if (!call_new_handler(nothrow, size))
      break;
  }
  return ptr;
}

// new.cpp
void* operator new(size_t size) {
  return generic_cpp_alloc(size, false);
}

// delete.cpp
void operator delete(void* p) throw() {
  free(p);
}

这里和CRT的实现已经无什么差异了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值