替换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的实现已经无什么差异了。