[llvm-commits] [compiler-rt] r145463 - in /compiler-rt/trunk/lib/asan: ./ mach_override/ scripts/ sysinfo/ tests/

Kostya Serebryany kcc at google.com
Tue Nov 29 17:07:03 PST 2011


Author: kcc
Date: Tue Nov 29 19:07:02 2011
New Revision: 145463

URL: http://llvm.org/viewvc/llvm-project?rev=145463&view=rev
Log:
AddressSanitizer run-time library. Not yet integrated with the compiler-rt build system, but can be built using the old makefile. See details in README.txt

Added:
    compiler-rt/trunk/lib/asan/
    compiler-rt/trunk/lib/asan/Makefile.mk
    compiler-rt/trunk/lib/asan/Makefile.old
    compiler-rt/trunk/lib/asan/README.txt
    compiler-rt/trunk/lib/asan/asan_allocator.cc
    compiler-rt/trunk/lib/asan/asan_allocator.h
    compiler-rt/trunk/lib/asan/asan_globals.cc
    compiler-rt/trunk/lib/asan/asan_interceptors.cc
    compiler-rt/trunk/lib/asan/asan_interceptors.h
    compiler-rt/trunk/lib/asan/asan_interface.h
    compiler-rt/trunk/lib/asan/asan_internal.h
    compiler-rt/trunk/lib/asan/asan_linux.cc
    compiler-rt/trunk/lib/asan/asan_lock.h
    compiler-rt/trunk/lib/asan/asan_mac.cc
    compiler-rt/trunk/lib/asan/asan_mac.h
    compiler-rt/trunk/lib/asan/asan_malloc_linux.cc
    compiler-rt/trunk/lib/asan/asan_malloc_mac.cc
    compiler-rt/trunk/lib/asan/asan_mapping.h
    compiler-rt/trunk/lib/asan/asan_poisoning.cc
    compiler-rt/trunk/lib/asan/asan_printf.cc
    compiler-rt/trunk/lib/asan/asan_rtl.cc
    compiler-rt/trunk/lib/asan/asan_stack.cc
    compiler-rt/trunk/lib/asan/asan_stack.h
    compiler-rt/trunk/lib/asan/asan_stats.cc
    compiler-rt/trunk/lib/asan/asan_stats.h
    compiler-rt/trunk/lib/asan/asan_thread.cc
    compiler-rt/trunk/lib/asan/asan_thread.h
    compiler-rt/trunk/lib/asan/asan_thread_registry.cc
    compiler-rt/trunk/lib/asan/asan_thread_registry.h
    compiler-rt/trunk/lib/asan/mach_override/
    compiler-rt/trunk/lib/asan/mach_override/mach_override.c
    compiler-rt/trunk/lib/asan/mach_override/mach_override.h
    compiler-rt/trunk/lib/asan/scripts/
    compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py   (with props)
    compiler-rt/trunk/lib/asan/sysinfo/
    compiler-rt/trunk/lib/asan/sysinfo/basictypes.h
    compiler-rt/trunk/lib/asan/sysinfo/sysinfo.cc
    compiler-rt/trunk/lib/asan/sysinfo/sysinfo.h
    compiler-rt/trunk/lib/asan/tests/
    compiler-rt/trunk/lib/asan/tests/asan_benchmarks_test.cc
    compiler-rt/trunk/lib/asan/tests/asan_break_optimization.cc
    compiler-rt/trunk/lib/asan/tests/asan_globals_test.cc
    compiler-rt/trunk/lib/asan/tests/asan_interface_test.cc
    compiler-rt/trunk/lib/asan/tests/asan_mac_test.h
    compiler-rt/trunk/lib/asan/tests/asan_mac_test.mm
    compiler-rt/trunk/lib/asan/tests/asan_noinst_test.cc
    compiler-rt/trunk/lib/asan/tests/asan_test.cc
    compiler-rt/trunk/lib/asan/tests/asan_test.ignore
    compiler-rt/trunk/lib/asan/tests/asan_test_config.h
    compiler-rt/trunk/lib/asan/tests/asan_test_utils.h
    compiler-rt/trunk/lib/asan/tests/global-overflow.cc
    compiler-rt/trunk/lib/asan/tests/global-overflow.tmpl
    compiler-rt/trunk/lib/asan/tests/heap-overflow.cc
    compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl
    compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl.Darwin
    compiler-rt/trunk/lib/asan/tests/large_func_test.cc
    compiler-rt/trunk/lib/asan/tests/large_func_test.tmpl
    compiler-rt/trunk/lib/asan/tests/match_output.py   (with props)
    compiler-rt/trunk/lib/asan/tests/null_deref.cc
    compiler-rt/trunk/lib/asan/tests/null_deref.tmpl
    compiler-rt/trunk/lib/asan/tests/shared-lib-test-so.cc
    compiler-rt/trunk/lib/asan/tests/shared-lib-test.cc
    compiler-rt/trunk/lib/asan/tests/shared-lib-test.tmpl
    compiler-rt/trunk/lib/asan/tests/stack-overflow.cc
    compiler-rt/trunk/lib/asan/tests/stack-overflow.tmpl
    compiler-rt/trunk/lib/asan/tests/stack-use-after-return.cc
    compiler-rt/trunk/lib/asan/tests/stack-use-after-return.disabled
    compiler-rt/trunk/lib/asan/tests/strncpy-overflow.cc
    compiler-rt/trunk/lib/asan/tests/strncpy-overflow.tmpl
    compiler-rt/trunk/lib/asan/tests/test_output.sh   (with props)
    compiler-rt/trunk/lib/asan/tests/use-after-free.c
    compiler-rt/trunk/lib/asan/tests/use-after-free.cc
    compiler-rt/trunk/lib/asan/tests/use-after-free.tmpl

Added: compiler-rt/trunk/lib/asan/Makefile.mk
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/Makefile.mk?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/Makefile.mk (added)
+++ compiler-rt/trunk/lib/asan/Makefile.mk Tue Nov 29 19:07:02 2011
@@ -0,0 +1,10 @@
+#===- lib/asan/Makefile.mk ---------------------------------*- Makefile -*--===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+# See README.txt

Added: compiler-rt/trunk/lib/asan/Makefile.old
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/Makefile.old?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/Makefile.old (added)
+++ compiler-rt/trunk/lib/asan/Makefile.old Tue Nov 29 19:07:02 2011
@@ -0,0 +1,360 @@
+#===- lib/asan/Makefile.old --------------------------------*- Makefile -*--===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+SVNVERSION=$(shell svnversion)
+OS=$(shell uname | tr '[A-Z]' '[a-z]')
+ROOT=$(shell pwd)
+MAKEFILE=Makefile.old  # this file.
+
+ifeq ($(ARCH), android)
+  ANDROID_CFLAGS= \
+		-DANDROID \
+		-D__WORDSIZE=32 \
+		-I$(ANDROID_BUILD_TOP)/external/stlport/stlport \
+		-I$(ANDROID_BUILD_TOP)/bionic \
+		-I$(ANDROID_BUILD_TOP)/bionic/libstdc++/include \
+		-I$(ANDROID_BUILD_TOP)/bionic/libc/arch-arm/include \
+		-I$(ANDROID_BUILD_TOP)/bionic/libc/include \
+		-I$(ANDROID_BUILD_TOP)/bionic/libc/kernel/common \
+		-I$(ANDROID_BUILD_TOP)/bionic/libc/kernel/arch-arm \
+		-I$(ANDROID_BUILD_TOP)/bionic/libm/include \
+		-I$(ANDROID_BUILD_TOP)/bionic/libm/include/arm \
+		-I$(ANDROID_BUILD_TOP)/bionic/libthread_db/include \
+		-L$(ANDROID_PRODUCT_OUT)/obj/lib
+  CLANG_FLAGS= \
+		-ccc-host-triple arm-linux-androideabi \
+		-D__compiler_offsetof=__builtin_offsetof \
+		-D__ELF__=1 \
+		-ccc-gcc-name arm-linux-androideabi-g++ \
+		$(ANDROID_CFLAGS)
+  CC=$(ANDROID_EABI_TOOLCHAIN)/arm-linux-androideabi-gcc $(ANDROID_CFLAGS)
+  CXX=$(ANDROID_EABI_TOOLCHAIN)/arm-linux-androideabi-g++ $(ANDROID_CFLAGS)
+endif
+
+ifeq ($(ARCH), arm)
+  # Example make command line:
+  # CROSSTOOL=$HOME/x-tools/arm-unknown-linux-gnueabi/ PATH=$CROSSTOOL/bin:$PATH make ARCH=arm asan_test
+  CLANG_FLAGS= \
+		-ccc-host-triple arm-unknown-linux-gnueabi \
+		-march=armv7-a -mfloat-abi=softfp -mfp=neon \
+		-ccc-gcc-name arm-unknown-linux-gnueabi-g++ \
+		-B$(CROSSTOOL)/lib/gcc/arm-unknown-linux-gnueabi/4.4.4 \
+		-B$(CROSSTOOL)/arm-unknown-linux-gnueabi/sys-root/usr/lib \
+		-I$(CROSSTOOL)/lib/gcc/arm-unknown-linux-gnueabi/4.4.4/include \
+		-I$(CROSSTOOL)/arm-unknown-linux-gnueabi/include/c++/4.4.4 \
+		-I$(CROSSTOOL)/arm-unknown-linux-gnueabi/include/c++/4.4.4/arm-unknown-linux-gnueabi \
+		-I$(CROSSTOOL)/arm-unknown-linux-gnueabi/sys-root/include \
+		-I$(CROSSTOOL)/arm-unknown-linux-gnueabi/sys-root/usr/include \
+		-L$(CROSSTOOL)/lib/gcc/arm-unknown-linux-gnueabi/4.4.4 \
+		-L$(CROSSTOOL)/arm-unknown-linux-gnueabi/sys-root/lib \
+		-L$(CROSSTOOL)/arm-unknown-linux-gnueabi/sys-root/usr/lib
+  CC=$(CROSSTOOL)/bin/arm-unknown-linux-gnueabi-gcc 
+  CXX=$(CROSSTOOL)/bin/arm-unknown-linux-gnueabi-g++
+endif
+
+CLANG_FLAGS=
+CLANG_BUILD=$(ROOT)/../../../../build/Release+Asserts
+CLANG_CC=$(CLANG_BUILD)/bin/clang $(CLANG_FLAGS)
+CLANG_CXX=$(CLANG_BUILD)/bin/clang++ $(CLANG_FLAGS)
+
+CC=$(CLANG_CC)
+CXX=$(CLANG_CXX)
+
+CFLAGS:=-Wall -fvisibility=hidden
+
+CLEANROOM_CXX=$(CXX) -Wall
+
+INSTALL_DIR=../asan_clang_$(OS)
+BIN=bin_$(OS)
+
+LIBS=#-lpthread -ldl
+ARCH=x86_64
+
+ASAN_STACK=1
+ASAN_GLOBALS=1
+ASAN_USE_CALL=1
+ASAN_SCALE=0  # default will be used
+ASAN_OFFSET=-1  #default will be used
+ASAN_UAR=0
+ASAN_HAS_EXCEPTIONS=1
+ASAN_FLEXIBLE_MAPPING_AND_OFFSET=0
+ASAN_HAS_BLACKLIST=1
+ASAN_NEEDS_SEGV=1
+ASAN_PIE=0
+
+ifeq ($(ARCH), i386)
+BITS=32
+SUFF=$(BITS)
+CFLAGS:=$(CFLAGS) -m$(BITS)
+endif
+
+ifeq ($(ARCH), x86_64)
+BITS=64
+SUFF=$(BITS)
+CFLAGS:=$(CFLAGS) -m$(BITS)
+endif
+
+ifeq ($(ARCH), arm)
+BITS=32
+SUFF=_arm
+CFLAGS:=$(CFLAGS) -march=armv7-a
+ASAN_HAS_EXCEPTIONS=0
+endif
+
+ifeq ($(ARCH), android)
+BITS=32
+SUFF=_android
+CFLAGS:=$(CFLAGS)
+ASAN_HAS_EXCEPTIONS=0
+endif
+
+PIE=
+ifeq ($(ASAN_PIE), 1)
+  PIE=-fPIE -pie
+endif
+
+LIBASAN_INST_DIR=$(CLANG_BUILD)/lib/clang/$(OS)/$(ARCH)
+LIBASAN_A=$(LIBASAN_INST_DIR)/libclang_rt.asan.a
+
+BLACKLIST=
+ifeq ($(ASAN_HAS_BLACKLIST), 1)
+  BLACKLIST=-mllvm -asan-blacklist=$(ROOT)/tests/asan_test.ignore
+endif
+
+COMMON_ASAN_DEFINES=\
+                -DASAN_UAR=$(ASAN_UAR) \
+		-DASAN_HAS_EXCEPTIONS=$(ASAN_HAS_EXCEPTIONS) \
+		-DASAN_NEEDS_SEGV=$(ASAN_NEEDS_SEGV) \
+		-DASAN_HAS_BLACKLIST=$(ASAN_HAS_BLACKLIST)
+
+CLANG_ASAN_CXX=$(CLANG_CXX) \
+	       -faddress-sanitizer \
+	       -DADDRESS_SANITIZER=1 \
+		$(BLACKLIST)  \
+		-mllvm -asan-stack=$(ASAN_STACK)      \
+		-mllvm -asan-globals=$(ASAN_GLOBALS)  \
+		-mllvm -asan-use-call=$(ASAN_USE_CALL) \
+		-mllvm -asan-mapping-scale=$(ASAN_SCALE) \
+		-mllvm -asan-mapping-offset-log=$(ASAN_OFFSET) \
+		-mllvm -asan-use-after-return=$(ASAN_UAR) \
+		$(COMMON_ASAN_DEFINES)
+
+CLANG_ASAN_LD=$(CLANG_CXX) -faddress-sanitizer
+
+GCC_ASAN_PATH=SET_FROM_COMMAND_LINE
+GCC_ASAN_CXX=$(GCC_ASAN_PATH)/g++ \
+	     -faddress-sanitizer \
+	     -DADDRESS_SANITIZER=1 \
+	     $(COMMON_ASAN_DEFINES)
+
+GCC_ASAN_LD=$(GCC_ASAN_PATH)/g++ -ldl -lpthread
+
+ASAN_COMPILER=clang
+
+ifeq ($(ASAN_COMPILER), clang)
+  ASAN_CXX=$(CLANG_ASAN_CXX)
+  ASAN_LD=$(CLANG_ASAN_LD)
+  ASAN_LD_TAIL=
+endif
+
+ifeq ($(ASAN_COMPILER), gcc)
+  ASAN_CXX=$(GCC_ASAN_CXX)
+  ASAN_LD=$(GCC_ASAN_LD)
+  ASAN_LD_TAIL=$(LIBASAN_A)
+endif
+
+RTL_HDR_COMMON=asan_allocator.h \
+	asan_internal.h \
+	asan_interceptors.h \
+	asan_interface.h \
+	asan_lock.h \
+	asan_mapping.h \
+	asan_stack.h \
+	asan_stats.h \
+	asan_thread.h \
+	asan_thread_registry.h \
+	sysinfo/basictypes.h \
+	sysinfo/sysinfo.h
+
+LIBASAN_OBJ_COMMON=$(BIN)/asan_rtl$(SUFF).o \
+	    $(BIN)/asan_allocator$(SUFF).o  \
+	    $(BIN)/asan_globals$(SUFF).o  \
+	    $(BIN)/asan_interceptors$(SUFF).o  \
+	    $(BIN)/asan_poisoning$(SUFF).o  \
+	    $(BIN)/asan_printf$(SUFF).o  \
+	    $(BIN)/asan_stack$(SUFF).o  \
+	    $(BIN)/asan_stats$(SUFF).o  \
+	    $(BIN)/asan_thread$(SUFF).o  \
+	    $(BIN)/asan_thread_registry$(SUFF).o  \
+	    $(BIN)/sysinfo/sysinfo$(SUFF).o
+
+ifeq ($(OS),Darwin)
+RTL_HDR=$(RTL_HDR_COMMON) mach_override/mach_override.h asan_mac.h
+LIBASAN_OBJ=$(LIBASAN_OBJ_COMMON) \
+	    $(BIN)/asan_mac$(SUFF).o \
+	    $(BIN)/asan_malloc_mac$(SUFF).o \
+	    $(BIN)/mach_override/mach_override$(SUFF).o
+else
+RTL_HDR=$(RTL_HDR_COMMON)
+LIBASAN_OBJ=$(LIBASAN_OBJ_COMMON) \
+	    $(BIN)/asan_linux$(SUFF).o \
+	    $(BIN)/asan_malloc_linux$(SUFF).o
+endif
+
+GTEST_ROOT=third_party/googletest
+GTEST_INCLUDE=-I$(GTEST_ROOT)/include
+GTEST_MAKE_DIR=$(GTEST_ROOT)/make-$(OS)$(SUFF)
+GTEST_LIB=$(GTEST_MAKE_DIR)/gtest-all.o
+
+all: b64 b32
+
+test: t64 t32 output_tests lint
+
+output_tests: b32 b64
+	cd tests && ./test_output.sh $(CLANG_CXX)
+
+t64: b64
+	$(BIN)/asan_test64
+t32: b32
+	$(BIN)/asan_test32
+
+b64: | $(BIN)
+	$(MAKE) -f $(MAKEFILE) ARCH=x86_64 asan_test asan_benchmarks
+b32: | $(BIN)
+	$(MAKE) -f $(MAKEFILE) ARCH=i386 asan_test asan_benchmarks
+
+lib64:
+	$(MAKE) $(MAKEFILE) ARCH=x86_64 lib
+lib32:
+	$(MAKE) $(MAKEFILE) ARCH=i386 lib
+
+$(BIN):
+	mkdir -p $(BIN)
+	mkdir -p $(BIN)/sysinfo
+	mkdir -p $(BIN)/mach_override
+
+clang:
+	cd ../ && llvm/rebuild_clang_and_asan.sh > /dev/null
+
+install: install_clang
+
+$(INSTALL_DIR):
+	mkdir -p $(INSTALL_DIR) $(INSTALL_DIR)/bin $(INSTALL_DIR)/lib
+
+install_clang: | $(INSTALL_DIR)
+	cp -v $(CLANG_BUILD)/bin/clang $(INSTALL_DIR)/bin
+	cp -rv $(CLANG_BUILD)/lib/clang $(INSTALL_DIR)/lib
+	(cd $(INSTALL_DIR)/bin; ln -sf clang clang++)
+
+#install_lib: | $(INSTALL_DIR)
+#	cp -v $(CLANG_BUILD)/lib/libasan*.a $(INSTALL_DIR)/lib
+
+$(BIN)/asan_noinst_test$(SUFF).o: tests/asan_noinst_test.cc $(RTL_HDR) $(MAKEFILE)
+	$(CLEANROOM_CXX) $(PIE) $(CFLAGS) $(GTEST_INCLUDE) -I. -g -c $< -O2 -o $@
+
+$(BIN)/asan_break_optimization$(SUFF).o: tests/asan_break_optimization.cc $(MAKEFILE)
+	$(CLEANROOM_CXX) $(PIE) $(CFLAGS) -c $< -O0 -o $@
+
+$(BIN)/%_test$(SUFF).o: tests/%_test.cc $(RTL_HDR) $(MAKEFILE)
+	$(ASAN_CXX) $(GTEST_INCLUDE) -I. -g -c $< -O2 -o $@ $(PIE) $(CFLAGS)
+
+$(BIN)/%_test$(SUFF).o: tests/%_test.mm $(RTL_HDR) $(MAKEFILE)
+	$(ASAN_CXX) $(GTEST_INCLUDE) -I. -g -c $< -O2 -o $@ -ObjC $(PIE) $(CFLAGS)
+
+$(BIN)/%$(SUFF).o: %.cc $(RTL_HDR) $(MAKEFILE)
+	$(CXX) $(PIE) $(CFLAGS) -fPIC -c -o $@ -g $< -Ithird_party \
+		-DASAN_REVISION=\"$(SVNVERSION)\" \
+		-DASAN_USE_SYSINFO=1 \
+		-DASAN_NEEDS_SEGV=$(ASAN_NEEDS_SEGV) \
+		-DASAN_HAS_EXCEPTIONS=$(ASAN_HAS_EXCEPTIONS) \
+		-DASAN_FLEXIBLE_MAPPING_AND_OFFSET=$(ASAN_FLEXIBLE_MAPPING_AND_OFFSET) \
+		$(ASAN_FLAGS)
+
+$(BIN)/%$(SUFF).o: %.c $(RTL_HDR) $(MAKEFILE)
+	$(CC) $(PIE) $(CFLAGS) -fPIC -c -o $@ -g $< -Ithird_party \
+		-DASAN_REVISION=\"$(SVNVERSION)\" \
+		-DASAN_USE_SYSINFO=1 \
+		$(ASAN_FLAGS)
+
+ifeq ($(OS),Darwin)
+LD_FLAGS=-framework Foundation
+else
+LD_FLAGS=
+endif
+
+lib: $(LIBASAN_A)
+
+$(LIBASAN_A): $(BIN) $(LIBASAN_OBJ) $(MAKEFILE)
+	mkdir -p $(LIBASAN_INST_DIR)
+	ar ru $@ $(LIBASAN_OBJ)
+	$(CXX) -shared $(CFLAGS) $(LIBASAN_OBJ) $(LD_FLAGS) -o $(BIN)/libasan$(SUFF).so
+
+
+TEST_OBJECTS_COMMON=\
+	     $(BIN)/asan_test$(SUFF).o \
+	     $(BIN)/asan_globals_test$(SUFF).o \
+	     $(BIN)/asan_break_optimization$(SUFF).o \
+	     $(BIN)/asan_noinst_test$(SUFF).o \
+	     $(BIN)/asan_interface_test$(SUFF).o
+
+BENCHMARK_OBJECTS=\
+	     $(BIN)/asan_benchmarks_test$(SUFF).o \
+	     $(BIN)/asan_break_optimization$(SUFF).o
+
+ifeq ($(OS),Darwin)
+TEST_OBJECTS=$(TEST_OBJECTS_COMMON) \
+	     $(BIN)/asan_mac_test$(SUFF).o
+else
+TEST_OBJECTS=$(TEST_OBJECTS_COMMON)
+endif
+
+$(BIN)/asan_test$(SUFF): $(TEST_OBJECTS) $(LIBASAN_A) $(MAKEFILE) tests/asan_test.ignore $(GTEST_LIB)
+	$(ASAN_LD) $(PIE) $(CFLAGS) -g -O3 $(TEST_OBJECTS) \
+		$(LD_FLAGS) -o $@ $(LIBS) $(GTEST_LIB) $(ASAN_LD_TAIL)
+
+$(BIN)/asan_benchmarks$(SUFF): $(BENCHMARK_OBJECTS) $(LIBASAN_A) $(MAKEFILE) $(GTEST_LIB)
+	$(ASAN_LD) $(PIE) $(CFLAGS) -g -O3 $(BENCHMARK_OBJECTS) \
+		$(LD_FLAGS) -o $@ $(LIBS) $(GTEST_LIB) $(ASAN_LD_TAIL)
+
+asan_test: $(BIN)/asan_test$(SUFF)
+
+asan_benchmarks: $(BIN)/asan_benchmarks$(SUFF)
+
+# for now, build gtest with clang/asan even if we use a different compiler.
+$(GTEST_LIB):
+	mkdir -p $(GTEST_MAKE_DIR) && \
+	cd $(GTEST_MAKE_DIR) && \
+	$(MAKE) -f ../make/Makefile CXXFLAGS="$(PIE) $(CFLAGS) -g -w" \
+	  CXX="$(CLANG_ASAN_CXX)"
+
+RTL_LINT_FITLER=-readability/casting,-readability/check,-build/include,-build/header_guard,-build/class,-legal/copyright
+# TODO(kcc): remove these filters one by one
+TEST_LINT_FITLER=-readability/casting,-build/include,-legal/copyright,-whitespace/newline,-runtime/sizeof,-runtime/int,-runtime/printf
+
+LLVM_LINT_FILTER=-,+whitespace
+
+ADDRESS_SANITIZER_CPP=../../../../lib/Transforms/Instrumentation/AddressSanitizer.cpp
+
+lint:
+	third_party/cpplint/cpplint.py --filter=$(LLVM_LINT_FILTER) $(ADDRESS_SANITIZER_CPP)
+	third_party/cpplint/cpplint.py --filter=$(RTL_LINT_FITLER) asan_*.cc asan_*.h
+	third_party/cpplint/cpplint.py --filter=$(TEST_LINT_FITLER) tests/*.cc
+
+get_third_party:
+	rm -rf third_party
+	mkdir third_party
+	(cd third_party && \
+	svn co -r375        http://googletest.googlecode.com/svn/trunk googletest && \
+	svn co -r69 http://google-styleguide.googlecode.com/svn/trunk/cpplint cpplint \
+	)
+
+clean:
+	rm -f *.o *.ll *.S *.a *.log asan_test64* asan_test32*  a.out perf.data log
+	rm -rf $(BIN)
+	rm -rf $(GTEST_ROOT)/make-*

Added: compiler-rt/trunk/lib/asan/README.txt
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/README.txt?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/README.txt (added)
+++ compiler-rt/trunk/lib/asan/README.txt Tue Nov 29 19:07:02 2011
@@ -0,0 +1,26 @@
+AddressSanitizer RT
+================================
+This directory contains sources of the AddressSanitizer (asan) run-time library.
+We are in the process of integrating AddressSanitizer with LLVM, stay tuned.
+
+Directory structre:
+
+README.txt       : This file.
+Makefile.mk      : Currently a stub for a proper makefile. not usable.
+Makefile.old     : Old out-of-tree makefile, the only usable one so far.
+asan_*.{cc,h}    : Sources of the asan run-time lirbary.
+mach_override/*  : Utility to override functions on Darwin (MIT License).
+sysinfo/*        : Portable utility to iterate over /proc/maps (BSD License).
+scripts/*        : Helper scripts.
+
+Temporary build instructions (verified on linux):
+
+cd lib/asan
+make -f Makefile.old get_third_party  # gets googletest and cpplint
+make -f Makefile.old test -j 8 CLANG_BUILD=/path/to/Release+Asserts
+# Optional:
+# make -f Makefile.old install # installs clang and rt to lib/asan_clang_linux
+
+For more info see http://code.google.com/p/address-sanitizer/
+
+

Added: compiler-rt/trunk/lib/asan/asan_allocator.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_allocator.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,1065 @@
+//===-- asan_allocator.cc ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Implementation of ASan's memory allocator.
+// Evey piece of memory (AsanChunk) allocated by the allocator
+// has a left redzone of REDZONE bytes and
+// a right redzone such that the end of the chunk is aligned by REDZONE
+// (i.e. the right redzone is between 0 and REDZONE-1).
+// The left redzone is always poisoned.
+// The right redzone is poisoned on malloc, the body is poisoned on free.
+// Once freed, a chunk is moved to a quarantine (fifo list).
+// After quarantine, a chunk is returned to freelists.
+//
+// The left redzone contains ASan's internal data and the stack trace of
+// the malloc call.
+// Once freed, the body of the chunk contains the stack trace of the free call.
+//
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_lock.h"
+#include "asan_mapping.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+#include "asan_thread_registry.h"
+
+#include <sys/mman.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <algorithm>
+
+namespace __asan {
+
+#define  REDZONE FLAG_redzone
+static const size_t kMinAllocSize = REDZONE * 2;
+static const size_t kMinMmapSize  = 4UL << 20;  // 4M
+static const uint64_t kMaxAvailableRam = 128ULL << 30;  // 128G
+static const size_t kMaxThreadLocalQuarantine = 1 << 20;  // 1M
+static const size_t kMaxSizeForThreadLocalFreeList = 1 << 17;
+
+// Size classes less than kMallocSizeClassStep are powers of two.
+// All other size classes are multiples of kMallocSizeClassStep.
+static const size_t kMallocSizeClassStepLog = 26;
+static const size_t kMallocSizeClassStep = 1UL << kMallocSizeClassStepLog;
+
+#if __WORDSIZE == 32
+static const size_t kMaxAllowedMallocSize = 3UL << 30;  // 3G
+#else
+static const size_t kMaxAllowedMallocSize = 8UL << 30;  // 8G
+#endif
+
+static void OutOfMemoryMessage(const char *mem_type, size_t size) {
+  AsanThread *t = asanThreadRegistry().GetCurrent();
+  CHECK(t);
+  Report("ERROR: AddressSanitizer failed to allocate "
+         "0x%lx (%lu) bytes (%s) in T%d\n",
+         size, size, mem_type, t->tid());
+}
+
+static inline bool IsAligned(uintptr_t a, uintptr_t alignment) {
+  return (a & (alignment - 1)) == 0;
+}
+
+static inline bool IsPowerOfTwo(size_t x) {
+  return (x & (x - 1)) == 0;
+}
+
+static inline size_t Log2(size_t x) {
+  CHECK(IsPowerOfTwo(x));
+  return __builtin_ctzl(x);
+}
+
+static inline size_t RoundUpTo(size_t size, size_t boundary) {
+  CHECK(IsPowerOfTwo(boundary));
+  return (size + boundary - 1) & ~(boundary - 1);
+}
+
+static inline size_t RoundUpToPowerOfTwo(size_t size) {
+  CHECK(size);
+  if (IsPowerOfTwo(size)) return size;
+  size_t up = __WORDSIZE - __builtin_clzl(size);
+  CHECK(size < (1ULL << up));
+  CHECK(size > (1ULL << (up - 1)));
+  return 1UL << up;
+}
+
+static inline size_t SizeClassToSize(uint8_t size_class) {
+  CHECK(size_class < kNumberOfSizeClasses);
+  if (size_class <= kMallocSizeClassStepLog) {
+    return 1UL << size_class;
+  } else {
+    return (size_class - kMallocSizeClassStepLog) * kMallocSizeClassStep;
+  }
+}
+
+static inline uint8_t SizeToSizeClass(size_t size) {
+  uint8_t res = 0;
+  if (size <= kMallocSizeClassStep) {
+    size_t rounded = RoundUpToPowerOfTwo(size);
+    res = Log2(rounded);
+  } else {
+    res = ((size + kMallocSizeClassStep - 1) / kMallocSizeClassStep)
+        + kMallocSizeClassStepLog;
+  }
+  CHECK(res < kNumberOfSizeClasses);
+  CHECK(size <= SizeClassToSize(res));
+  return res;
+}
+
+static void PoisonShadow(uintptr_t mem, size_t size, uint8_t poison) {
+  CHECK(IsAligned(mem,        SHADOW_GRANULARITY));
+  CHECK(IsAligned(mem + size, SHADOW_GRANULARITY));
+  uintptr_t shadow_beg = MemToShadow(mem);
+  uintptr_t shadow_end = MemToShadow(mem + size);
+  real_memset((void*)shadow_beg, poison, shadow_end - shadow_beg);
+}
+
+// Given REDZONE bytes, we need to mark first size bytes
+// as addressable and the rest REDZONE-size bytes as unaddressable.
+static void PoisonMemoryPartialRightRedzone(uintptr_t mem, size_t size) {
+  CHECK(size <= REDZONE);
+  CHECK(IsAligned(mem, REDZONE));
+  CHECK(IsPowerOfTwo(SHADOW_GRANULARITY));
+  CHECK(IsPowerOfTwo(REDZONE));
+  CHECK(REDZONE >= SHADOW_GRANULARITY);
+  uint8_t *shadow = (uint8_t*)MemToShadow(mem);
+  PoisonShadowPartialRightRedzone(shadow, size,
+                                  REDZONE, SHADOW_GRANULARITY,
+                                  kAsanHeapRightRedzoneMagic);
+}
+
+static uint8_t *MmapNewPagesAndPoisonShadow(size_t size) {
+  CHECK(IsAligned(size, kPageSize));
+  uint8_t *res = (uint8_t*)asan_mmap(0, size,
+                   PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANON, -1, 0);
+  if (res == (uint8_t*)-1) {
+    OutOfMemoryMessage(__FUNCTION__, size);
+    PRINT_CURRENT_STACK();
+    ASAN_DIE;
+  }
+  PoisonShadow((uintptr_t)res, size, kAsanHeapLeftRedzoneMagic);
+  if (FLAG_debug) {
+    Printf("ASAN_MMAP: [%p, %p)\n", res, res + size);
+  }
+  return res;
+}
+
+// Every chunk of memory allocated by this allocator can be in one of 3 states:
+// CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated.
+// CHUNK_ALLOCATED: the chunk is allocated and not yet freed.
+// CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone.
+//
+// The pseudo state CHUNK_MEMALIGN is used to mark that the address is not
+// the beginning of a AsanChunk (in which case 'next' contains the address
+// of the AsanChunk).
+//
+// The magic numbers for the enum values are taken randomly.
+enum {
+  CHUNK_AVAILABLE  = 0x573B,
+  CHUNK_ALLOCATED  = 0x3204,
+  CHUNK_QUARANTINE = 0x1978,
+  CHUNK_MEMALIGN   = 0xDC68,
+};
+
+struct ChunkBase {
+  uint16_t   chunk_state;
+  uint8_t    size_class;
+  uint32_t   offset;  // User-visible memory starts at this+offset (beg()).
+  int32_t    alloc_tid;
+  int32_t    free_tid;
+  size_t     used_size;  // Size requested by the user.
+  AsanChunk *next;
+
+  uintptr_t   beg() { return (uintptr_t)this + offset; }
+  size_t Size() { return SizeClassToSize(size_class); }
+  uint8_t SizeClass() { return size_class; }
+};
+
+struct AsanChunk: public ChunkBase {
+  uint32_t *compressed_alloc_stack() {
+    CHECK(REDZONE >= sizeof(ChunkBase));
+    return (uint32_t*)((uintptr_t)this + sizeof(ChunkBase));
+  }
+  uint32_t *compressed_free_stack() {
+    CHECK(REDZONE >= sizeof(ChunkBase));
+    return (uint32_t*)((uintptr_t)this + REDZONE);
+  }
+
+  // The left redzone after the ChunkBase is given to the alloc stack trace.
+  size_t compressed_alloc_stack_size() {
+    return (REDZONE - sizeof(ChunkBase)) / sizeof(uint32_t);
+  }
+  size_t compressed_free_stack_size() {
+    return (REDZONE) / sizeof(uint32_t);
+  }
+
+  bool AddrIsInside(uintptr_t addr, size_t access_size, size_t *offset) {
+    if (addr >= beg() && (addr + access_size) <= (beg() + used_size)) {
+      *offset = addr - beg();
+      return true;
+    }
+    return false;
+  }
+
+  bool AddrIsAtLeft(uintptr_t addr, size_t access_size, size_t *offset) {
+    if (addr < beg()) {
+      *offset = beg() - addr;
+      return true;
+    }
+    return false;
+  }
+
+  bool AddrIsAtRight(uintptr_t addr, size_t access_size, size_t *offset) {
+    if (addr + access_size >= beg() + used_size) {
+      if (addr <= beg() + used_size)
+        *offset = 0;
+      else
+        *offset = addr - (beg() + used_size);
+      return true;
+    }
+    return false;
+  }
+
+  void DescribeAddress(uintptr_t addr, size_t access_size) {
+    size_t offset;
+    Printf("%p is located ", addr);
+    if (AddrIsInside(addr, access_size, &offset)) {
+      Printf("%ld bytes inside of", offset);
+    } else if (AddrIsAtLeft(addr, access_size, &offset)) {
+      Printf("%ld bytes to the left of", offset);
+    } else if (AddrIsAtRight(addr, access_size, &offset)) {
+      Printf("%ld bytes to the right of", offset);
+    } else {
+      Printf(" somewhere around (this is AddressSanitizer bug!)");
+    }
+    Printf(" %lu-byte region [%p,%p)\n",
+           used_size, beg(), beg() + used_size);
+  }
+};
+
+static AsanChunk *PtrToChunk(uintptr_t ptr) {
+  AsanChunk *m = (AsanChunk*)(ptr - REDZONE);
+  if (m->chunk_state == CHUNK_MEMALIGN) {
+    m = m->next;
+  }
+  return m;
+}
+
+
+void AsanChunkFifoList::PushList(AsanChunkFifoList *q) {
+  if (last_) {
+    CHECK(first_);
+    CHECK(!last_->next);
+    last_->next = q->first_;
+    last_ = q->last_;
+  } else {
+    CHECK(!first_);
+    last_ = q->last_;
+    first_ = q->first_;
+  }
+  size_ += q->size();
+  q->clear();
+}
+
+void AsanChunkFifoList::Push(AsanChunk *n) {
+  CHECK(n->next == NULL);
+  if (last_) {
+    CHECK(first_);
+    CHECK(!last_->next);
+    last_->next = n;
+    last_ = n;
+  } else {
+    CHECK(!first_);
+    last_ = first_ = n;
+  }
+  size_ += n->Size();
+}
+
+// Interesting performance observation: this function takes up to 15% of overal
+// allocator time. That's because *first_ has been evicted from cache long time
+// ago. Not sure if we can or want to do anything with this.
+AsanChunk *AsanChunkFifoList::Pop() {
+  CHECK(first_);
+  AsanChunk *res = first_;
+  first_ = first_->next;
+  if (first_ == NULL)
+    last_ = NULL;
+  CHECK(size_ >= res->Size());
+  size_ -= res->Size();
+  if (last_) {
+    CHECK(!last_->next);
+  }
+  return res;
+}
+
+// All pages we ever allocated.
+struct PageGroup {
+  uintptr_t beg;
+  uintptr_t end;
+  size_t size_of_chunk;
+  uintptr_t last_chunk;
+  bool InRange(uintptr_t addr) {
+    return addr >= beg && addr < end;
+  }
+};
+
+class MallocInfo {
+ public:
+
+  explicit MallocInfo(LinkerInitialized x) : mu_(x) { }
+
+  AsanChunk *AllocateChunks(uint8_t size_class, size_t n_chunks) {
+    AsanChunk *m = NULL;
+    AsanChunk **fl = &free_lists_[size_class];
+    {
+      ScopedLock lock(&mu_);
+      for (size_t i = 0; i < n_chunks; i++) {
+        if (!(*fl)) {
+          *fl = GetNewChunks(size_class);
+        }
+        AsanChunk *t = *fl;
+        *fl = t->next;
+        t->next = m;
+        CHECK(t->chunk_state == CHUNK_AVAILABLE);
+        m = t;
+      }
+    }
+    return m;
+  }
+
+  void SwallowThreadLocalMallocStorage(AsanThreadLocalMallocStorage *x,
+                                       bool eat_free_lists) {
+    CHECK(FLAG_quarantine_size > 0);
+    ScopedLock lock(&mu_);
+    AsanChunkFifoList *q = &x->quarantine_;
+    if (q->size() > 0) {
+      quarantine_.PushList(q);
+      while (quarantine_.size() > FLAG_quarantine_size) {
+        QuarantinePop();
+      }
+    }
+    if (eat_free_lists) {
+      for (size_t size_class = 0; size_class < kNumberOfSizeClasses;
+           size_class++) {
+        AsanChunk *m = x->free_lists_[size_class];
+        while (m) {
+          AsanChunk *t = m->next;
+          m->next = free_lists_[size_class];
+          free_lists_[size_class] = m;
+          m = t;
+        }
+        x->free_lists_[size_class] = 0;
+      }
+    }
+  }
+
+  void BypassThreadLocalQuarantine(AsanChunk *chunk) {
+    ScopedLock lock(&mu_);
+    quarantine_.Push(chunk);
+  }
+
+  AsanChunk *FindMallocedOrFreed(uintptr_t addr, size_t access_size) {
+    ScopedLock lock(&mu_);
+    return FindChunkByAddr(addr);
+  }
+
+  // TODO(glider): AllocationSize() may become very slow if the size of
+  // page_groups_ grows. This can be fixed by increasing kMinMmapSize,
+  // but a better solution is to speed up the search somehow.
+  size_t AllocationSize(uintptr_t ptr) {
+    ScopedLock lock(&mu_);
+
+    // first, check if this is our memory
+    PageGroup *g = FindPageGroupUnlocked(ptr);
+    if (!g) return 0;
+    AsanChunk *m = PtrToChunk(ptr);
+    if (m->chunk_state == CHUNK_ALLOCATED) {
+      return m->used_size;
+    } else {
+      return 0;
+    }
+  }
+
+  void ForceLock() {
+    mu_.Lock();
+  }
+
+  void ForceUnlock() {
+    mu_.Unlock();
+  }
+
+  void PrintStatus() {
+    ScopedLock lock(&mu_);
+    size_t malloced = 0;
+
+    Printf(" MallocInfo: in quarantine: %ld malloced: %ld; ",
+           quarantine_.size() >> 20, malloced >> 20);
+    for (size_t j = 1; j < kNumberOfSizeClasses; j++) {
+      AsanChunk *i = free_lists_[j];
+      if (!i) continue;
+      size_t t = 0;
+      for (; i; i = i->next) {
+        t += i->Size();
+      }
+      Printf("%ld:%ld ", j, t >> 20);
+    }
+    Printf("\n");
+  }
+
+  PageGroup *FindPageGroup(uintptr_t addr) {
+    ScopedLock lock(&mu_);
+    return FindPageGroupUnlocked(addr);
+  }
+
+ private:
+  PageGroup *FindPageGroupUnlocked(uintptr_t addr) {
+    for (int i = 0; i < n_page_groups_; i++) {
+      PageGroup *g = page_groups_[i];
+      if (g->InRange(addr)) {
+        return g;
+      }
+    }
+    return NULL;
+  }
+
+  // We have an address between two chunks, and we want to report just one.
+  AsanChunk *ChooseChunk(uintptr_t addr,
+                         AsanChunk *left_chunk, AsanChunk *right_chunk) {
+    // Prefer an allocated chunk or a chunk from quarantine.
+    if (left_chunk->chunk_state == CHUNK_AVAILABLE &&
+        right_chunk->chunk_state != CHUNK_AVAILABLE)
+      return right_chunk;
+    if (right_chunk->chunk_state == CHUNK_AVAILABLE &&
+        left_chunk->chunk_state != CHUNK_AVAILABLE)
+      return left_chunk;
+    // Choose based on offset.
+    uintptr_t l_offset = 0, r_offset = 0;
+    CHECK(left_chunk->AddrIsAtRight(addr, 1, &l_offset));
+    CHECK(right_chunk->AddrIsAtLeft(addr, 1, &r_offset));
+    if (l_offset < r_offset)
+      return left_chunk;
+    return right_chunk;
+  }
+
+  AsanChunk *FindChunkByAddr(uintptr_t addr) {
+    PageGroup *g = FindPageGroupUnlocked(addr);
+    if (!g) return 0;
+    CHECK(g->size_of_chunk);
+    uintptr_t offset_from_beg = addr - g->beg;
+    uintptr_t this_chunk_addr = g->beg +
+        (offset_from_beg / g->size_of_chunk) * g->size_of_chunk;
+    CHECK(g->InRange(this_chunk_addr));
+    AsanChunk *m = (AsanChunk*)this_chunk_addr;
+    CHECK(m->chunk_state == CHUNK_ALLOCATED ||
+          m->chunk_state == CHUNK_AVAILABLE ||
+          m->chunk_state == CHUNK_QUARANTINE);
+    uintptr_t offset = 0;
+    if (m->AddrIsInside(addr, 1, &offset))
+      return m;
+
+    if (m->AddrIsAtRight(addr, 1, &offset)) {
+      if (this_chunk_addr == g->last_chunk)  // rightmost chunk
+        return m;
+      uintptr_t right_chunk_addr = this_chunk_addr + g->size_of_chunk;
+      CHECK(g->InRange(right_chunk_addr));
+      return ChooseChunk(addr, m, (AsanChunk*)right_chunk_addr);
+    } else {
+      CHECK(m->AddrIsAtLeft(addr, 1, &offset));
+      if (this_chunk_addr == g->beg)  // leftmost chunk
+        return m;
+      uintptr_t left_chunk_addr = this_chunk_addr - g->size_of_chunk;
+      CHECK(g->InRange(left_chunk_addr));
+      return ChooseChunk(addr, (AsanChunk*)left_chunk_addr, m);
+    }
+  }
+
+  void QuarantinePop() {
+    CHECK(quarantine_.size() > 0);
+    AsanChunk *m = quarantine_.Pop();
+    CHECK(m);
+    // if (F_v >= 2) Printf("MallocInfo::pop %p\n", m);
+
+    CHECK(m->chunk_state == CHUNK_QUARANTINE);
+    m->chunk_state = CHUNK_AVAILABLE;
+    CHECK(m->alloc_tid >= 0);
+    CHECK(m->free_tid >= 0);
+
+    size_t size_class = m->SizeClass();
+    m->next = free_lists_[size_class];
+    free_lists_[size_class] = m;
+
+    if (FLAG_stats) {
+      AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+      thread_stats.real_frees++;
+      thread_stats.really_freed += m->used_size;
+      thread_stats.really_freed_redzones += m->Size() - m->used_size;
+      thread_stats.really_freed_by_size[m->SizeClass()]++;
+    }
+  }
+
+  // Get a list of newly allocated chunks.
+  AsanChunk *GetNewChunks(uint8_t size_class) {
+    size_t size = SizeClassToSize(size_class);
+    CHECK(IsPowerOfTwo(kMinMmapSize));
+    CHECK(size < kMinMmapSize || (size % kMinMmapSize) == 0);
+    size_t mmap_size = std::max(size, kMinMmapSize);
+    size_t n_chunks = mmap_size / size;
+    CHECK(n_chunks * size == mmap_size);
+    if (size < kPageSize) {
+      // Size is small, just poison the last chunk.
+      n_chunks--;
+    } else {
+      // Size is large, allocate an extra page at right and poison it.
+      mmap_size += kPageSize;
+    }
+    CHECK(n_chunks > 0);
+    uint8_t *mem = MmapNewPagesAndPoisonShadow(mmap_size);
+    if (FLAG_stats) {
+      AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+      thread_stats.mmaps++;
+      thread_stats.mmaped += mmap_size;
+      thread_stats.mmaped_by_size[size_class] += n_chunks;
+    }
+    AsanChunk *res = NULL;
+    for (size_t i = 0; i < n_chunks; i++) {
+      AsanChunk *m = (AsanChunk*)(mem + i * size);
+      m->chunk_state = CHUNK_AVAILABLE;
+      m->size_class = size_class;
+      m->next = res;
+      res = m;
+    }
+    PageGroup *pg = (PageGroup*)(mem + n_chunks * size);
+    // This memory is already poisoned, no need to poison it again.
+    pg->beg = (uintptr_t)mem;
+    pg->end = pg->beg + mmap_size;
+    pg->size_of_chunk = size;
+    pg->last_chunk = (uintptr_t)(mem + size * (n_chunks - 1));
+    int page_group_idx = AtomicInc(&n_page_groups_) - 1;
+    CHECK(page_group_idx < (int)ASAN_ARRAY_SIZE(page_groups_));
+    page_groups_[page_group_idx] = pg;
+    return res;
+  }
+
+  AsanChunk *free_lists_[kNumberOfSizeClasses];
+  AsanChunkFifoList quarantine_;
+  AsanLock mu_;
+
+  PageGroup *page_groups_[kMaxAvailableRam / kMinMmapSize];
+  int n_page_groups_;  // atomic
+};
+
+static MallocInfo malloc_info(LINKER_INITIALIZED);
+
+void AsanThreadLocalMallocStorage::CommitBack() {
+  malloc_info.SwallowThreadLocalMallocStorage(this, true);
+}
+
+static void Describe(uintptr_t addr, size_t access_size) {
+  AsanChunk *m = malloc_info.FindMallocedOrFreed(addr, access_size);
+  if (!m) return;
+  m->DescribeAddress(addr, access_size);
+  CHECK(m->alloc_tid >= 0);
+  AsanThreadSummary *alloc_thread =
+      asanThreadRegistry().FindByTid(m->alloc_tid);
+  AsanStackTrace alloc_stack;
+  AsanStackTrace::UncompressStack(&alloc_stack, m->compressed_alloc_stack(),
+                                  m->compressed_alloc_stack_size());
+  AsanThread *t = asanThreadRegistry().GetCurrent();
+  CHECK(t);
+  if (m->free_tid >= 0) {
+    AsanThreadSummary *free_thread =
+        asanThreadRegistry().FindByTid(m->free_tid);
+    Printf("freed by thread T%d here:\n", free_thread->tid());
+    AsanStackTrace free_stack;
+    AsanStackTrace::UncompressStack(&free_stack, m->compressed_free_stack(),
+                                    m->compressed_free_stack_size());
+    free_stack.PrintStack();
+    Printf("previously allocated by thread T%d here:\n",
+           alloc_thread->tid());
+
+    alloc_stack.PrintStack();
+    t->summary()->Announce();
+    free_thread->Announce();
+    alloc_thread->Announce();
+  } else {
+    Printf("allocated by thread T%d here:\n", alloc_thread->tid());
+    alloc_stack.PrintStack();
+    t->summary()->Announce();
+    alloc_thread->Announce();
+  }
+}
+
+static uint8_t *Allocate(size_t alignment, size_t size, AsanStackTrace *stack) {
+  __asan_init();
+  CHECK(stack);
+  if (size == 0) {
+    size = 1;  // TODO(kcc): do something smarter
+  }
+  CHECK(IsPowerOfTwo(alignment));
+  size_t rounded_size = RoundUpTo(size, REDZONE);
+  size_t needed_size = rounded_size + REDZONE;
+  if (alignment > REDZONE) {
+    needed_size += alignment;
+  }
+  CHECK(IsAligned(needed_size, REDZONE));
+  if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
+    Report("WARNING: AddressSanitizer failed to allocate %p bytes\n", size);
+    return 0;
+  }
+
+  uint8_t size_class = SizeToSizeClass(needed_size);
+  size_t size_to_allocate = SizeClassToSize(size_class);
+  CHECK(size_to_allocate >= kMinAllocSize);
+  CHECK(size_to_allocate >= needed_size);
+  CHECK(IsAligned(size_to_allocate, REDZONE));
+
+  if (FLAG_v >= 2) {
+    Printf("Allocate align: %ld size: %ld class: %d real: %ld\n",
+         alignment, size, size_class, size_to_allocate);
+  }
+
+  AsanThread *t = asanThreadRegistry().GetCurrent();
+  AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+  if (FLAG_stats) {
+    thread_stats.mallocs++;
+    thread_stats.malloced += size;
+    thread_stats.malloced_redzones += size_to_allocate - size;
+    thread_stats.malloced_by_size[size_class]++;
+  }
+
+  AsanChunk *m = NULL;
+  if (!t || size_to_allocate >= kMaxSizeForThreadLocalFreeList) {
+    // get directly from global storage.
+    m = malloc_info.AllocateChunks(size_class, 1);
+    if (FLAG_stats) {
+      thread_stats.malloc_large++;
+    }
+  } else {
+    // get from the thread-local storage.
+    AsanChunk **fl = &t->malloc_storage().free_lists_[size_class];
+    if (!*fl) {
+      size_t n_new_chunks = kMaxSizeForThreadLocalFreeList / size_to_allocate;
+      // n_new_chunks = std::min((size_t)32, n_new_chunks);
+      *fl = malloc_info.AllocateChunks(size_class, n_new_chunks);
+      if (FLAG_stats) {
+        thread_stats.malloc_small_slow++;
+      }
+    }
+    m = *fl;
+    *fl = (*fl)->next;
+  }
+  CHECK(m);
+  CHECK(m->chunk_state == CHUNK_AVAILABLE);
+  m->chunk_state = CHUNK_ALLOCATED;
+  m->next = NULL;
+  CHECK(m->Size() == size_to_allocate);
+  uintptr_t addr = (uintptr_t)m + REDZONE;
+  CHECK(addr == (uintptr_t)m->compressed_free_stack());
+
+  if (alignment > REDZONE && (addr & (alignment - 1))) {
+    addr = RoundUpTo(addr, alignment);
+    CHECK((addr & (alignment - 1)) == 0);
+    AsanChunk *p = (AsanChunk*)(addr - REDZONE);
+    p->chunk_state = CHUNK_MEMALIGN;
+    p->next = m;
+  }
+  CHECK(m == PtrToChunk(addr));
+  m->used_size = size;
+  m->offset = addr - (uintptr_t)m;
+  CHECK(m->beg() == addr);
+  m->alloc_tid = t ? t->tid() : 0;
+  m->free_tid   = AsanThread::kInvalidTid;
+  AsanStackTrace::CompressStack(stack, m->compressed_alloc_stack(),
+                                m->compressed_alloc_stack_size());
+  PoisonShadow(addr, rounded_size, 0);
+  if (size < rounded_size) {
+    PoisonMemoryPartialRightRedzone(addr + rounded_size - REDZONE,
+                                    size & (REDZONE - 1));
+  }
+  if (size <= FLAG_max_malloc_fill_size) {
+    real_memset((void*)addr, 0, rounded_size);
+  }
+  return (uint8_t*)addr;
+}
+
+static void Deallocate(uint8_t *ptr, AsanStackTrace *stack) {
+  if (!ptr) return;
+  CHECK(stack);
+
+  if (FLAG_debug) {
+    CHECK(malloc_info.FindPageGroup((uintptr_t)ptr));
+  }
+
+  // Printf("Deallocate %p\n", ptr);
+  AsanChunk *m = PtrToChunk((uintptr_t)ptr);
+  if (m->chunk_state == CHUNK_QUARANTINE) {
+    Printf("attempting double-free on %p:\n", ptr);
+    stack->PrintStack();
+    m->DescribeAddress((uintptr_t)ptr, 1);
+    ShowStatsAndAbort();
+  } else if (m->chunk_state != CHUNK_ALLOCATED) {
+    Printf("attempting free on address which was not malloc()-ed: %p\n", ptr);
+    stack->PrintStack();
+    ShowStatsAndAbort();
+  }
+  CHECK(m->chunk_state == CHUNK_ALLOCATED);
+  CHECK(m->free_tid == AsanThread::kInvalidTid);
+  CHECK(m->alloc_tid >= 0);
+  AsanThread *t = asanThreadRegistry().GetCurrent();
+  m->free_tid = t ? t->tid() : 0;
+  AsanStackTrace::CompressStack(stack, m->compressed_free_stack(),
+                                m->compressed_free_stack_size());
+  size_t rounded_size = RoundUpTo(m->used_size, REDZONE);
+  PoisonShadow((uintptr_t)ptr, rounded_size, kAsanHeapFreeMagic);
+
+  if (FLAG_stats) {
+    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+    thread_stats.frees++;
+    thread_stats.freed += m->used_size;
+    thread_stats.freed_by_size[m->SizeClass()]++;
+  }
+
+  m->chunk_state = CHUNK_QUARANTINE;
+  if (t) {
+    AsanThreadLocalMallocStorage *ms = &t->malloc_storage();
+    CHECK(!m->next);
+    ms->quarantine_.Push(m);
+
+    if (ms->quarantine_.size() > kMaxThreadLocalQuarantine) {
+      malloc_info.SwallowThreadLocalMallocStorage(ms, false);
+    }
+  } else {
+    CHECK(!m->next);
+    malloc_info.BypassThreadLocalQuarantine(m);
+  }
+}
+
+static uint8_t *Reallocate(uint8_t *old_ptr, size_t new_size,
+                           AsanStackTrace *stack) {
+  CHECK(old_ptr && new_size);
+  if (FLAG_stats) {
+    AsanStats &thread_stats = asanThreadRegistry().GetCurrentThreadStats();
+    thread_stats.reallocs++;
+    thread_stats.realloced += new_size;
+  }
+  AsanChunk *m = PtrToChunk((uintptr_t)old_ptr);
+  CHECK(m->chunk_state == CHUNK_ALLOCATED);
+  size_t old_size = m->used_size;
+  size_t memcpy_size = std::min(new_size, old_size);
+  uint8_t *new_ptr = Allocate(0, new_size, stack);
+  if (new_ptr) {
+    real_memcpy(new_ptr, old_ptr, memcpy_size);
+    Deallocate(old_ptr, stack);
+  }
+  return new_ptr;
+}
+
+}  // namespace __asan
+
+// Malloc hooks declaration.
+// ASAN_NEW_HOOK(ptr, size) is called immediately after
+//   allocation of "size" bytes, which returned "ptr".
+// ASAN_DELETE_HOOK(ptr) is called immediately before
+//   deallocation of "ptr".
+// If ASAN_NEW_HOOK or ASAN_DELETE_HOOK is defined, user
+// program must provide implementation of this hook.
+// If macro is undefined, the hook is no-op.
+#ifdef ASAN_NEW_HOOK
+extern "C" void ASAN_NEW_HOOK(void *ptr, size_t size);
+#else
+static inline void ASAN_NEW_HOOK(void *ptr, size_t size) { }
+#endif
+
+#ifdef ASAN_DELETE_HOOK
+extern "C" void ASAN_DELETE_HOOK(void *ptr);
+#else
+static inline void ASAN_DELETE_HOOK(void *ptr) { }
+#endif
+
+namespace __asan {
+
+void *asan_memalign(size_t alignment, size_t size, AsanStackTrace *stack) {
+  void *ptr = (void*)Allocate(alignment, size, stack);
+  ASAN_NEW_HOOK(ptr, size);
+  return ptr;
+}
+
+void asan_free(void *ptr, AsanStackTrace *stack) {
+  ASAN_DELETE_HOOK(ptr);
+  Deallocate((uint8_t*)ptr, stack);
+}
+
+void *asan_malloc(size_t size, AsanStackTrace *stack) {
+  void *ptr = (void*)Allocate(0, size, stack);
+  ASAN_NEW_HOOK(ptr, size);
+  return ptr;
+}
+
+void *asan_calloc(size_t nmemb, size_t size, AsanStackTrace *stack) {
+  void *ptr = (void*)Allocate(0, nmemb * size, stack);
+  if (ptr)
+    real_memset(ptr, 0, nmemb * size);
+  ASAN_NEW_HOOK(ptr, nmemb * size);
+  return ptr;
+}
+
+void *asan_realloc(void *p, size_t size, AsanStackTrace *stack) {
+  if (p == NULL) {
+    void *ptr = (void*)Allocate(0, size, stack);
+    ASAN_NEW_HOOK(ptr, size);
+    return ptr;
+  } else if (size == 0) {
+    ASAN_DELETE_HOOK(p);
+    Deallocate((uint8_t*)p, stack);
+    return NULL;
+  }
+  return Reallocate((uint8_t*)p, size, stack);
+}
+
+void *asan_valloc(size_t size, AsanStackTrace *stack) {
+  void *ptr = (void*)Allocate(kPageSize, size, stack);
+  ASAN_NEW_HOOK(ptr, size);
+  return ptr;
+}
+
+void *asan_pvalloc(size_t size, AsanStackTrace *stack) {
+  size = RoundUpTo(size, kPageSize);
+  if (size == 0) {
+    // pvalloc(0) should allocate one page.
+    size = kPageSize;
+  }
+  void *ptr = (void*)Allocate(kPageSize, size, stack);
+  ASAN_NEW_HOOK(ptr, size);
+  return ptr;
+}
+
+int asan_posix_memalign(void **memptr, size_t alignment, size_t size,
+                          AsanStackTrace *stack) {
+  void *ptr = Allocate(alignment, size, stack);
+  CHECK(IsAligned((uintptr_t)ptr, alignment));
+  ASAN_NEW_HOOK(ptr, size);
+  *memptr = ptr;
+  return 0;
+}
+
+size_t __asan_mz_size(const void *ptr) {
+  return malloc_info.AllocationSize((uintptr_t)ptr);
+}
+
+void DescribeHeapAddress(uintptr_t addr, uintptr_t access_size) {
+  Describe(addr, access_size);
+}
+
+void __asan_mz_force_lock() {
+  malloc_info.ForceLock();
+}
+
+void __asan_mz_force_unlock() {
+  malloc_info.ForceUnlock();
+}
+
+// ---------------------- Fake stack-------------------- {{{1
+FakeStack::FakeStack() {
+  CHECK(real_memset);
+  real_memset(this, 0, sizeof(*this));
+}
+
+bool FakeStack::AddrIsInSizeClass(uintptr_t addr, size_t size_class) {
+  uintptr_t mem = allocated_size_classes_[size_class];
+  uintptr_t size = ClassMmapSize(size_class);
+  bool res = mem && addr >= mem && addr < mem + size;
+  return res;
+}
+
+uintptr_t FakeStack::AddrIsInFakeStack(uintptr_t addr) {
+  if (!alive_) return 0;
+  for (size_t i = 0; i < kNumberOfSizeClasses; i++) {
+    if (AddrIsInSizeClass(addr, i)) return allocated_size_classes_[i];
+  }
+  return 0;
+}
+
+// We may want to compute this during compilation.
+inline size_t FakeStack::ComputeSizeClass(size_t alloc_size) {
+  size_t rounded_size = RoundUpToPowerOfTwo(alloc_size);
+  size_t log = Log2(rounded_size);
+  CHECK(alloc_size <= (1UL << log));
+  if (!(alloc_size > (1UL << (log-1)))) {
+    Printf("alloc_size %ld log %ld\n", alloc_size, log);
+  }
+  CHECK(alloc_size > (1UL << (log-1)));
+  size_t res = log < kMinStackFrameSizeLog ? 0 : log - kMinStackFrameSizeLog;
+  CHECK(res < kNumberOfSizeClasses);
+  CHECK(ClassSize(res) >= rounded_size);
+  return res;
+}
+
+void FakeFrameFifo::FifoPush(FakeFrame *node) {
+  CHECK(node);
+  node->next = 0;
+  if (first_ == 0 && last_ == 0) {
+    first_ = last_ = node;
+  } else {
+    CHECK(first_);
+    CHECK(last_);
+    last_->next = node;
+    last_ = node;
+  }
+}
+
+FakeFrame *FakeFrameFifo::FifoPop() {
+  CHECK(first_ && last_ && "Exhausted fake stack");
+  FakeFrame *res = 0;
+  if (first_ == last_) {
+    res = first_;
+    first_ = last_ = 0;
+  } else {
+    res = first_;
+    first_ = first_->next;
+  }
+  return res;
+}
+
+void FakeStack::Init(size_t stack_size) {
+  stack_size_ = stack_size;
+  alive_ = true;
+}
+
+void FakeStack::Cleanup() {
+  alive_ = false;
+  for (size_t i = 0; i < kNumberOfSizeClasses; i++) {
+    uintptr_t mem = allocated_size_classes_[i];
+    if (mem) {
+      PoisonShadow(mem, ClassMmapSize(i), 0);
+      allocated_size_classes_[i] = 0;
+      int munmap_res = munmap((void*)mem, ClassMmapSize(i));
+      CHECK(munmap_res == 0);
+    }
+  }
+}
+
+size_t FakeStack::ClassMmapSize(size_t size_class) {
+  return RoundUpToPowerOfTwo(stack_size_);
+}
+
+void FakeStack::AllocateOneSizeClass(size_t size_class) {
+  CHECK(ClassMmapSize(size_class) >= kPageSize);
+  uintptr_t new_mem = (uintptr_t)asan_mmap(0, ClassMmapSize(size_class),
+                                             PROT_READ | PROT_WRITE,
+                                             MAP_PRIVATE | MAP_ANON, -1, 0);
+  CHECK(new_mem != (uintptr_t)-1);
+  // Printf("T%d new_mem[%ld]: %p-%p mmap %ld\n",
+  //       asanThreadRegistry().GetCurrent()->tid(),
+  //       size_class, new_mem, new_mem + ClassMmapSize(size_class),
+  //       ClassMmapSize(size_class));
+  size_t i;
+  for (i = 0; i < ClassMmapSize(size_class);
+       i += ClassSize(size_class)) {
+    size_classes_[size_class].FifoPush((FakeFrame*)(new_mem + i));
+  }
+  CHECK(i == ClassMmapSize(size_class));
+  allocated_size_classes_[size_class] = new_mem;
+}
+
+uintptr_t FakeStack::AllocateStack(size_t size, size_t real_stack) {
+  CHECK(alive_);
+  CHECK(size <= kMaxStackMallocSize && size > 1);
+  size_t size_class = ComputeSizeClass(size);
+  if (!allocated_size_classes_[size_class]) {
+    AllocateOneSizeClass(size_class);
+  }
+  FakeFrame *fake_frame = size_classes_[size_class].FifoPop();
+  CHECK(fake_frame);
+  fake_frame->size_minus_one = size - 1;
+  fake_frame->real_stack = real_stack;
+  while (FakeFrame *top = call_stack_.top()) {
+    if (top->real_stack > real_stack) break;
+    call_stack_.LifoPop();
+    DeallocateFrame(top);
+  }
+  call_stack_.LifoPush(fake_frame);
+  uintptr_t ptr = (uintptr_t)fake_frame;
+  PoisonShadow(ptr, size, 0);
+  return ptr;
+}
+
+void FakeStack::DeallocateFrame(FakeFrame *fake_frame) {
+  CHECK(alive_);
+  size_t size = fake_frame->size_minus_one + 1;
+  size_t size_class = ComputeSizeClass(size);
+  CHECK(allocated_size_classes_[size_class]);
+  uintptr_t ptr = (uintptr_t)fake_frame;
+  CHECK(AddrIsInSizeClass(ptr, size_class));
+  CHECK(AddrIsInSizeClass(ptr + size - 1, size_class));
+  size_classes_[size_class].FifoPush(fake_frame);
+}
+
+void FakeStack::OnFree(size_t ptr, size_t size, size_t real_stack) {
+  FakeFrame *fake_frame = (FakeFrame*)ptr;
+  CHECK(fake_frame->magic = kRetiredStackFrameMagic);
+  CHECK(fake_frame->descr != 0);
+  CHECK(fake_frame->size_minus_one == size - 1);
+  PoisonShadow(ptr, size, kAsanStackAfterReturnMagic);
+}
+
+}  // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan;  // NOLINT
+
+size_t __asan_stack_malloc(size_t size, size_t real_stack) {
+  if (!FLAG_use_fake_stack) return real_stack;
+  AsanThread *t = asanThreadRegistry().GetCurrent();
+  if (!t) {
+    // TSD is gone, use the real stack.
+    return real_stack;
+  }
+  size_t ptr = t->fake_stack().AllocateStack(size, real_stack);
+  // Printf("__asan_stack_malloc %p %ld %p\n", ptr, size, real_stack);
+  return ptr;
+}
+
+void __asan_stack_free(size_t ptr, size_t size, size_t real_stack) {
+  if (!FLAG_use_fake_stack) return;
+  if (ptr != real_stack) {
+    FakeStack::OnFree(ptr, size, real_stack);
+  }
+}
+
+// ASan allocator doesn't reserve extra bytes, so normally we would
+// just return "size".
+size_t __asan_get_estimated_allocated_size(size_t size) {
+  if (size == 0) return 1;
+  return std::min(size, kMaxAllowedMallocSize);
+}
+
+bool __asan_get_ownership(const void *p) {
+  return (p == NULL) ||
+      (malloc_info.AllocationSize((uintptr_t)p) > 0);
+}
+
+size_t __asan_get_allocated_size(const void *p) {
+  if (p == NULL) return 0;
+  size_t allocated_size = malloc_info.AllocationSize((uintptr_t)p);
+  // Die if p is not malloced or if it is already freed.
+  if (allocated_size == 0) {
+    Printf("__asan_get_allocated_size failed, ptr=%p is not owned\n", p);
+    PRINT_CURRENT_STACK();
+    ShowStatsAndAbort();
+  }
+  return allocated_size;
+}

Added: compiler-rt/trunk/lib/asan/asan_allocator.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator.h (added)
+++ compiler-rt/trunk/lib/asan/asan_allocator.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,156 @@
+//===-- asan_allocator.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_allocator.cc.
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_ALLOCATOR_H
+#define ASAN_ALLOCATOR_H
+
+#include "asan_internal.h"
+#include "asan_interceptors.h"
+
+namespace __asan {
+
+static const size_t kNumberOfSizeClasses = 255;
+class AsanChunk;
+
+class AsanChunkFifoList {
+ public:
+  explicit AsanChunkFifoList(LinkerInitialized) { }
+  AsanChunkFifoList() { clear(); }
+  void Push(AsanChunk *n);
+  void PushList(AsanChunkFifoList *q);
+  AsanChunk *Pop();
+  size_t size() { return size_; }
+  void clear() {
+    first_ = last_ = NULL;
+    size_ = 0;
+  }
+ private:
+  AsanChunk *first_;
+  AsanChunk *last_;
+  size_t size_;
+};
+
+struct AsanThreadLocalMallocStorage {
+  explicit AsanThreadLocalMallocStorage(LinkerInitialized x)
+      : quarantine_(x) { }
+  AsanThreadLocalMallocStorage() {
+    CHECK(real_memset);
+    real_memset(this, 0, sizeof(AsanThreadLocalMallocStorage));
+  }
+
+  AsanChunkFifoList quarantine_;
+  AsanChunk *free_lists_[kNumberOfSizeClasses];
+  void CommitBack();
+};
+
+// Fake stack frame contains local variables of one function.
+// This struct should fit into a stack redzone (32 bytes).
+struct FakeFrame {
+  uintptr_t magic;  // Modified by the instrumented code.
+  uintptr_t descr;  // Modified by the instrumented code.
+  FakeFrame *next;
+  uint64_t real_stack     : 48;
+  uint64_t size_minus_one : 16;
+};
+
+struct FakeFrameFifo {
+ public:
+  void FifoPush(FakeFrame *node);
+  FakeFrame *FifoPop();
+ private:
+  FakeFrame *first_, *last_;
+};
+
+class FakeFrameLifo {
+ public:
+  void LifoPush(FakeFrame *node) {
+    node->next = top_;
+    top_ = node;
+  }
+  void LifoPop() {
+    CHECK(top_);
+    top_ = top_->next;
+  }
+  FakeFrame *top() { return top_; }
+ private:
+  FakeFrame *top_;
+};
+
+// For each thread we create a fake stack and place stack objects on this fake
+// stack instead of the real stack. The fake stack is not really a stack but
+// a fast malloc-like allocator so that when a function exits the fake stack
+// is not poped but remains there for quite some time until gets used again.
+// So, we poison the objects on the fake stack when function returns.
+// It helps us find use-after-return bugs.
+// We can not rely on __asan_stack_free being called on every function exit,
+// so we maintain a lifo list of all current fake frames and update it on every
+// call to __asan_stack_malloc.
+class FakeStack {
+ public:
+  FakeStack();
+  explicit FakeStack(LinkerInitialized) {}
+  void Init(size_t stack_size);
+  void Cleanup();
+  uintptr_t AllocateStack(size_t size, size_t real_stack);
+  static void OnFree(size_t ptr, size_t size, size_t real_stack);
+  // Return the bottom of the maped region.
+  uintptr_t AddrIsInFakeStack(uintptr_t addr);
+ private:
+  static const size_t kMinStackFrameSizeLog = 9;  // Min frame is 512B.
+  static const size_t kMaxStackFrameSizeLog = 16;  // Max stack frame is 64K.
+  static const size_t kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
+  static const size_t kNumberOfSizeClasses =
+      kMaxStackFrameSizeLog - kMinStackFrameSizeLog + 1;
+
+  bool AddrIsInSizeClass(uintptr_t addr, size_t size_class);
+
+  // Each size class should be large enough to hold all frames.
+  size_t ClassMmapSize(size_t size_class);
+
+  size_t ClassSize(size_t size_class) {
+    return 1UL << (size_class + kMinStackFrameSizeLog);
+  }
+
+  void DeallocateFrame(FakeFrame *fake_frame);
+
+  size_t ComputeSizeClass(size_t alloc_size);
+  void AllocateOneSizeClass(size_t size_class);
+
+  size_t stack_size_;
+  bool   alive_;
+
+  uintptr_t allocated_size_classes_[kNumberOfSizeClasses];
+  FakeFrameFifo size_classes_[kNumberOfSizeClasses];
+  FakeFrameLifo call_stack_;
+};
+
+void *asan_memalign(size_t alignment, size_t size, AsanStackTrace *stack);
+void asan_free(void *ptr, AsanStackTrace *stack);
+
+void *asan_malloc(size_t size, AsanStackTrace *stack);
+void *asan_calloc(size_t nmemb, size_t size, AsanStackTrace *stack);
+void *asan_realloc(void *p, size_t size, AsanStackTrace *stack);
+void *asan_valloc(size_t size, AsanStackTrace *stack);
+void *asan_pvalloc(size_t size, AsanStackTrace *stack);
+
+int asan_posix_memalign(void **memptr, size_t alignment, size_t size,
+                          AsanStackTrace *stack);
+
+size_t __asan_mz_size(const void *ptr);
+void __asan_mz_force_lock();
+void __asan_mz_force_unlock();
+void DescribeHeapAddress(uintptr_t addr, size_t access_size);
+
+}  // namespace __asan
+#endif  // ASAN_ALLOCATOR_H

Added: compiler-rt/trunk/lib/asan/asan_globals.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_globals.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_globals.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_globals.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,144 @@
+//===-- asan_globals.cc -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Handle globals.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_lock.h"
+#include "asan_mapping.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+
+#include <ctype.h>
+#include <map>
+
+namespace __asan {
+
+typedef __asan_global Global;
+
+static AsanLock mu_for_globals(LINKER_INITIALIZED);
+typedef std::map<uintptr_t, Global> MapOfGlobals;
+static MapOfGlobals *g_all_globals = NULL;
+
+void PoisonRedZones(const Global &g)  {
+  uintptr_t shadow = MemToShadow(g.beg);
+  size_t ShadowRZSize = kGlobalAndStackRedzone >> SHADOW_SCALE;
+  CHECK(ShadowRZSize == 1 || ShadowRZSize == 2 || ShadowRZSize == 4);
+  // full right redzone
+  uintptr_t right_rz2_offset = ShadowRZSize *
+      ((g.size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone);
+  real_memset((uint8_t*)shadow + right_rz2_offset,
+              kAsanGlobalRedzoneMagic, ShadowRZSize);
+  if ((g.size % kGlobalAndStackRedzone) != 0) {
+    // partial right redzone
+    uint64_t right_rz1_offset =
+        ShadowRZSize * (g.size / kGlobalAndStackRedzone);
+    CHECK(right_rz1_offset == right_rz2_offset - ShadowRZSize);
+    PoisonShadowPartialRightRedzone((uint8_t*)(shadow + right_rz1_offset),
+                                    g.size % kGlobalAndStackRedzone,
+                                    kGlobalAndStackRedzone,
+                                    SHADOW_GRANULARITY,
+                                    kAsanGlobalRedzoneMagic);
+  }
+}
+
+static size_t GetAlignedSize(size_t size) {
+  return ((size + kGlobalAndStackRedzone - 1) / kGlobalAndStackRedzone)
+      * kGlobalAndStackRedzone;
+}
+
+  // Check if the global is a zero-terminated ASCII string. If so, print it.
+void PrintIfASCII(const Global &g) {
+  for (size_t p = g.beg; p < g.beg + g.size - 1; p++) {
+    if (!isascii(*(char*)p)) return;
+  }
+  if (*(char*)(g.beg + g.size - 1) != 0) return;
+  Printf("  '%s' is ascii string '%s'\n", g.name, g.beg);
+}
+
+bool DescribeAddrIfMyRedZone(const Global &g, uintptr_t addr) {
+  if (addr < g.beg - kGlobalAndStackRedzone) return false;
+  if (addr >= g.beg + g.size_with_redzone) return false;
+  Printf("%p is located ", addr);
+  if (addr < g.beg) {
+    Printf("%d bytes to the left", g.beg - addr);
+  } else if (addr >= g.beg + g.size) {
+    Printf("%d bytes to the right", addr - (g.beg + g.size));
+  } else {
+    Printf("%d bytes inside", addr - g.beg);  // Can it happen?
+  }
+  Printf(" of global variable '%s' (0x%lx) of size %ld\n",
+         g.name, g.beg, g.size);
+  PrintIfASCII(g);
+  return true;
+}
+
+
+bool DescribeAddrIfGlobal(uintptr_t addr) {
+  if (!FLAG_report_globals) return false;
+  ScopedLock lock(&mu_for_globals);
+  if (!g_all_globals) return false;
+  bool res = false;
+  // Just iterate. May want to use binary search instead.
+  for (MapOfGlobals::iterator i = g_all_globals->begin(),
+       end = g_all_globals->end(); i != end; ++i) {
+    Global &g = i->second;
+    CHECK(i->first == g.beg);
+    if (FLAG_report_globals >= 2)
+      Printf("Search Global: beg=%p size=%ld name=%s\n",
+             g.beg, g.size, g.name);
+    res |= DescribeAddrIfMyRedZone(g, addr);
+  }
+  return res;
+}
+
+// Register a global variable.
+// This function may be called more than once for every global
+// so we store the globals in a map.
+static void RegisterGlobal(const Global *g) {
+  CHECK(asan_inited);
+  if (!FLAG_report_globals) return;
+  ScopedLock lock(&mu_for_globals);
+  if (!g_all_globals)
+    g_all_globals = new MapOfGlobals;
+  CHECK(AddrIsInMem(g->beg));
+  if (FLAG_report_globals >= 2)
+    Printf("Added Global: beg=%p size=%ld name=%s\n",
+           g->beg, g->size, g->name);
+  PoisonRedZones(*g);
+  (*g_all_globals)[g->beg] = *g;
+}
+
+}  // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan;  // NOLINT
+
+// Register one global with a default redzone.
+void __asan_register_global(uintptr_t addr, size_t size,
+                            const char *name) {
+  Global g;
+  g.beg = addr;
+  g.size = size;
+  g.size_with_redzone = GetAlignedSize(size) + kGlobalAndStackRedzone;
+  g.name = name;
+  RegisterGlobal(&g);
+}
+
+// Register an array of globals.
+void __asan_register_globals(__asan_global *globals, size_t n) {
+  for (size_t i = 0; i < n; i++) {
+    RegisterGlobal(&globals[i]);
+  }
+}

Added: compiler-rt/trunk/lib/asan/asan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interceptors.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interceptors.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_interceptors.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,304 @@
+//===-- asan_interceptors.cc ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Intercept various libc functions to catch buggy memory accesses there.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+
+#include "asan_allocator.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+
+#include <algorithm>
+#include <dlfcn.h>
+#include <string.h>
+
+namespace __asan {
+
+index_f       real_index;
+memcpy_f      real_memcpy;
+memmove_f     real_memmove;
+memset_f      real_memset;
+strchr_f      real_strchr;
+strcmp_f      real_strcmp;
+strcpy_f      real_strcpy;
+strdup_f      real_strdup;
+strlen_f      real_strlen;
+strncmp_f     real_strncmp;
+strncpy_f     real_strncpy;
+strnlen_f     real_strnlen;
+
+// Instruments read/write access to a single byte in memory.
+// On error calls __asan_report_error, which aborts the program.
+__attribute__((noinline))
+static void AccessAddress(uintptr_t address, bool isWrite) {
+  if (__asan_address_is_poisoned((void*)address)) {
+    GET_BP_PC_SP;
+    __asan_report_error(pc, bp, sp, address, isWrite, /* access_size */ 1);
+  }
+}
+
+// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
+// and ASAN_WRITE_RANGE as macro instead of function so
+// that no extra frames are created, and stack trace contains
+// relevant information only.
+
+// Instruments read/write access to a memory range.
+// More complex implementation is possible, for now just
+// checking the first and the last byte of a range.
+#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
+  if (size > 0) { \
+    uintptr_t ptr = (uintptr_t)(offset); \
+    AccessAddress(ptr, isWrite); \
+    AccessAddress(ptr + (size) - 1, isWrite); \
+  } \
+} while (0);
+
+#define ASAN_READ_RANGE(offset, size) do { \
+  ACCESS_MEMORY_RANGE(offset, size, false); \
+} while (0);
+
+#define ASAN_WRITE_RANGE(offset, size) do { \
+  ACCESS_MEMORY_RANGE(offset, size, true); \
+} while (0);
+
+// Behavior of functions like "memcpy" or "strcpy" is undefined
+// if memory intervals overlap. We report error in this case.
+// Macro is used to avoid creation of new frames.
+static inline bool RangesOverlap(const char *offset1, const char *offset2,
+                                 size_t length) {
+  return !((offset1 + length <= offset2) || (offset2 + length <= offset1));
+}
+#define CHECK_RANGES_OVERLAP(_offset1, _offset2, length) do { \
+  const char *offset1 = (const char*)_offset1; \
+  const char *offset2 = (const char*)_offset2; \
+  if (RangesOverlap((const char*)offset1, (const char*)offset2, \
+                    length)) { \
+    Printf("ERROR: AddressSanitizer strcpy-param-overlap: " \
+           "memory ranges [%p,%p) and [%p, %p) overlap\n", \
+           offset1, offset1 + length, offset2, offset2 + length); \
+    PRINT_CURRENT_STACK(); \
+    ShowStatsAndAbort(); \
+  } \
+} while (0);
+
+static inline void ensure_asan_inited() {
+  CHECK(!asan_init_is_running);
+  if (!asan_inited) {
+    __asan_init();
+  }
+}
+
+
+size_t internal_strlen(const char *s) {
+  size_t i = 0;
+  while (s[i]) i++;
+  return i;
+}
+
+size_t internal_strnlen(const char *s, size_t maxlen) {
+  if (real_strnlen != NULL) {
+    return real_strnlen(s, maxlen);
+  }
+  size_t i = 0;
+  while (i < maxlen && s[i]) i++;
+  return i;
+}
+
+void InitializeAsanInterceptors() {
+#ifndef __APPLE__
+  INTERCEPT_FUNCTION(index);
+#else
+  OVERRIDE_FUNCTION(index, WRAP(strchr));
+#endif
+#ifndef __APPLE__
+  INTERCEPT_FUNCTION(memcpy);
+  INTERCEPT_FUNCTION(memmove);
+  INTERCEPT_FUNCTION(memset);
+#else
+  real_memcpy = memcpy;
+  real_memmove = memmove;
+  real_memset = memset;
+#endif
+  INTERCEPT_FUNCTION(strchr);
+  INTERCEPT_FUNCTION(strcmp);
+  INTERCEPT_FUNCTION(strcpy);  // NOLINT
+  INTERCEPT_FUNCTION(strdup);
+  INTERCEPT_FUNCTION(strlen);
+  INTERCEPT_FUNCTION(strncmp);
+  INTERCEPT_FUNCTION(strncpy);
+#ifndef __APPLE__
+  INTERCEPT_FUNCTION(strnlen);
+#endif
+  if (FLAG_v > 0) {
+    Printf("AddressSanitizer: libc interceptors initialized\n");
+  }
+}
+
+}  // namespace __asan
+
+// ---------------------- Wrappers ---------------- {{{1
+using namespace __asan;  // NOLINT
+
+void *WRAP(memcpy)(void *to, const void *from, size_t size) {
+  // memcpy is called during __asan_init() from the internals
+  // of printf(...).
+  if (asan_init_is_running) {
+    return real_memcpy(to, from, size);
+  }
+  ensure_asan_inited();
+  if (FLAG_replace_intrin) {
+    CHECK_RANGES_OVERLAP(to, from, size);
+    ASAN_WRITE_RANGE(from, size);
+    ASAN_READ_RANGE(to, size);
+  }
+  return real_memcpy(to, from, size);
+}
+
+void *WRAP(memmove)(void *to, const void *from, size_t size) {
+  ensure_asan_inited();
+  if (FLAG_replace_intrin) {
+    ASAN_WRITE_RANGE(from, size);
+    ASAN_READ_RANGE(to, size);
+  }
+  return real_memmove(to, from, size);
+}
+
+void *WRAP(memset)(void *block, int c, size_t size) {
+  ensure_asan_inited();
+  if (FLAG_replace_intrin) {
+    ASAN_WRITE_RANGE(block, size);
+  }
+  return real_memset(block, c, size);
+}
+
+// Note that on Linux index and strchr are definined differently depending on
+// the compiler (gcc vs clang).
+// see __CORRECT_ISO_CPP_STRING_H_PROTO in /usr/include/string.h
+
+#ifndef __APPLE__
+char *WRAP(index)(const char *str, int c)
+  __attribute__((alias(WRAPPER_NAME(strchr))));
+#endif
+
+char *WRAP(strchr)(const char *str, int c) {
+  ensure_asan_inited();
+  char *result = real_strchr(str, c);
+  if (FLAG_replace_str) {
+    size_t bytes_read = (result ? result - str : real_strlen(str)) + 1;
+    ASAN_READ_RANGE(str, bytes_read);
+  }
+  return result;
+}
+
+static inline int CharCmp(unsigned char c1, unsigned char c2) {
+  return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
+}
+
+int WRAP(strcmp)(const char *s1, const char *s2) {
+  // strcmp is called from malloc_default_purgeable_zone()
+  // in __asan::ReplaceSystemAlloc() on Mac.
+  if (asan_init_is_running) {
+    return real_strcmp(s1, s2);
+  }
+  unsigned char c1, c2;
+  size_t i;
+  for (i = 0; ; i++) {
+    c1 = (unsigned char)s1[i];
+    c2 = (unsigned char)s2[i];
+    if (c1 != c2 || c1 == '\0') break;
+  }
+  ASAN_READ_RANGE(s1, i + 1);
+  ASAN_READ_RANGE(s2, i + 1);
+  return CharCmp(c1, c2);
+}
+
+char *WRAP(strcpy)(char *to, const char *from) {  // NOLINT
+  // strcpy is called from malloc_default_purgeable_zone()
+  // in __asan::ReplaceSystemAlloc() on Mac.
+  if (asan_init_is_running) {
+    return real_strcpy(to, from);
+  }
+  ensure_asan_inited();
+  if (FLAG_replace_str) {
+    size_t from_size = real_strlen(from) + 1;
+    CHECK_RANGES_OVERLAP(to, from, from_size);
+    ASAN_READ_RANGE(from, from_size);
+    ASAN_WRITE_RANGE(to, from_size);
+  }
+  return real_strcpy(to, from);
+}
+
+char *WRAP(strdup)(const char *s) {
+  ensure_asan_inited();
+  if (FLAG_replace_str) {
+    size_t length = real_strlen(s);
+    ASAN_READ_RANGE(s, length + 1);
+  }
+  return real_strdup(s);
+}
+
+size_t WRAP(strlen)(const char *s) {
+  // strlen is called from malloc_default_purgeable_zone()
+  // in __asan::ReplaceSystemAlloc() on Mac.
+  if (asan_init_is_running) {
+    return real_strlen(s);
+  }
+  ensure_asan_inited();
+  size_t length = real_strlen(s);
+  if (FLAG_replace_str) {
+    ASAN_READ_RANGE(s, length + 1);
+  }
+  return length;
+}
+
+int WRAP(strncmp)(const char *s1, const char *s2, size_t size) {
+  // strncmp is called from malloc_default_purgeable_zone()
+  // in __asan::ReplaceSystemAlloc() on Mac.
+  if (asan_init_is_running) {
+    return real_strncmp(s1, s2, size);
+  }
+  unsigned char c1 = 0, c2 = 0;
+  size_t i;
+  for (i = 0; i < size; i++) {
+    c1 = (unsigned char)s1[i];
+    c2 = (unsigned char)s2[i];
+    if (c1 != c2 || c1 == '\0') break;
+  }
+  ASAN_READ_RANGE(s1, std::min(i + 1, size));
+  ASAN_READ_RANGE(s2, std::min(i + 1, size));
+  return CharCmp(c1, c2);
+}
+
+char *WRAP(strncpy)(char *to, const char *from, size_t size) {
+  ensure_asan_inited();
+  if (FLAG_replace_str) {
+    size_t from_size = std::min(size, internal_strnlen(from, size) + 1);
+    CHECK_RANGES_OVERLAP(to, from, from_size);
+    ASAN_READ_RANGE(from, from_size);
+    ASAN_WRITE_RANGE(to, size);
+  }
+  return real_strncpy(to, from, size);
+}
+
+#ifndef __APPLE__
+size_t WRAP(strnlen)(const char *s, size_t maxlen) {
+  ensure_asan_inited();
+  size_t length = real_strnlen(s, maxlen);
+  if (FLAG_replace_str) {
+    ASAN_READ_RANGE(s, std::min(length + 1, maxlen));
+  }
+  return length;
+}
+#endif

Added: compiler-rt/trunk/lib/asan/asan_interceptors.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interceptors.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interceptors.h (added)
+++ compiler-rt/trunk/lib/asan/asan_interceptors.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,105 @@
+//===-- asan_interceptors.h -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_interceptors.cc
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERCEPTORS_H
+#define ASAN_INTERCEPTORS_H
+
+#include "asan_internal.h"
+
+// To replace weak system functions on Linux we just need to declare functions
+// with same names in our library and then obtain the real function pointers
+// using dlsym(). This is not so on Mac OS, where the two-level namespace makes
+// our replacement functions invisible to other libraries. This may be overcomed
+// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
+// libraries in Chromium were noticed when doing so.
+// Instead we use mach_override, a handy framework for patching functions at
+// runtime. To avoid possible name clashes, our replacement functions have
+// the "wrap_" prefix on Mac.
+//
+// After interception, the calls to system functions will be substituted by
+// calls to our interceptors. We store pointers to system function f()
+// in __asan::real_f().
+//
+// TODO(glider): mach_override_ptr() tends to spend too much time
+// in allocateBranchIsland(). This should be ok for real-word
+// application, but slows down our tests which fork too many children.
+#ifdef __APPLE__
+#include "mach_override.h"
+#define WRAP(x) wrap_##x
+#define WRAPPER_NAME(x) "wrap_"#x
+#define OVERRIDE_FUNCTION(oldfunc, newfunc)                             \
+  CHECK(0 == mach_override_ptr((void*)(oldfunc),                        \
+                               (void*)(newfunc),                        \
+                               (void**)&real_##oldfunc));               \
+  CHECK(real_##oldfunc != NULL);
+#define INTERCEPT_FUNCTION(func)                                        \
+  OVERRIDE_FUNCTION(func, WRAP(func))
+#else
+#define WRAP(x) x
+#define WRAPPER_NAME(x) #x
+#define INTERCEPT_FUNCTION(func)                                        \
+  CHECK((real_##func = (func##_f)dlsym(RTLD_NEXT, #func)));
+#endif
+
+#ifdef __APPLE__
+void *WRAP(memcpy)(void *to, const void *from, size_t size);
+void *WRAP(memmove)(void *to, const void *from, size_t size);
+void *WRAP(memset)(void *block, int c, size_t size);
+const char *WRAP(strchr)(const char *string, int c);
+int WRAP(strcmp)(const char *s1, const char *s2);
+char *WRAP(strcpy)(char *to, const char *from);  // NOLINT
+char *WRAP(strdup)(const char *s);
+size_t WRAP(strlen)(const char *s);
+int WRAP(strncmp)(const char *s1, const char *s2, size_t size);
+char *WRAP(strncpy)(char *to, const char *from, size_t size);
+#endif
+
+namespace __asan {
+
+typedef void* (*index_f)(const char *string, int c);
+typedef void* (*memcpy_f)(void *to, const void *from, size_t size);
+typedef void* (*memmove_f)(void *to, const void *from, size_t size);
+typedef void* (*memset_f)(void *block, int c, size_t size);
+typedef char* (*strchr_f)(const char *str, int c);
+typedef int (*strcmp_f)(const char *s1, const char *s2);
+typedef char* (*strcpy_f)(char *to, const char *from);
+typedef char* (*strdup_f)(const char *s);
+typedef size_t (*strlen_f)(const char *s);
+typedef int (*strncmp_f)(const char *s1, const char *s2, size_t size);
+typedef char* (*strncpy_f)(char *to, const char *from, size_t size);
+typedef size_t (*strnlen_f)(const char *s, size_t maxlen);
+
+// __asan::real_X() holds pointer to library implementation of X().
+extern index_f          real_index;
+extern memcpy_f         real_memcpy;
+extern memmove_f        real_memmove;
+extern memset_f         real_memset;
+extern strchr_f         real_strchr;
+extern strcmp_f         real_strcmp;
+extern strcpy_f         real_strcpy;
+extern strdup_f         real_strdup;
+extern strlen_f         real_strlen;
+extern strncmp_f        real_strncmp;
+extern strncpy_f        real_strncpy;
+extern strnlen_f        real_strnlen;
+
+// __asan::internal_X() is the implementation of X() for use in RTL.
+size_t internal_strlen(const char *s);
+size_t internal_strnlen(const char *s, size_t maxlen);
+
+// Initializes pointers to str*/mem* functions.
+void InitializeAsanInterceptors();
+
+}  // namespace __asan
+
+#endif  // ASAN_INTERCEPTORS_H

Added: compiler-rt/trunk/lib/asan/asan_interface.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_interface.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_interface.h (added)
+++ compiler-rt/trunk/lib/asan/asan_interface.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,135 @@
+//===-- asan_interface.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This header can be included by the instrumented program to fetch
+// data (mostly allocator statistics) from ASan runtime library.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERFACE_H
+#define ASAN_INTERFACE_H
+
+#include <stdint.h>  // for __WORDSIZE
+#include <stdlib.h>  // for size_t
+
+// This header should NOT include any other headers from ASan runtime.
+// All functions in this header are extern "C" and start with __asan_.
+
+extern "C" {
+  // This function should be called at the very beginning of the process,
+  // before any instrumented code is executed and before any call to malloc.
+  void __asan_init()
+      __attribute__((visibility("default")));
+
+  // This function should be called by the instrumented code.
+  // 'addr' is the address of a global variable called 'name' of 'size' bytes.
+  void __asan_register_global(uintptr_t addr, size_t size, const char *name)
+      __attribute__((visibility("default")));
+
+  // This structure describes an instrumented global variable.
+  struct __asan_global {
+    size_t beg;                // The address of the global.
+    size_t size;               // The original size of the global.
+    size_t size_with_redzone;  // The size with the redzone.
+    const char *name;          // Name as a C string.
+  };
+
+  // This function should be called by the instrumented code.
+  // gets an array of structures describing globals.
+  void __asan_register_globals(__asan_global *globals, size_t n)
+      __attribute__((visibility("default")));
+
+  // These two functions are used by the instrumented code in the
+  // use-after-return mode. __asan_stack_malloc allocates size bytes of
+  // fake stack and __asan_stack_free poisons it. real_stack is a pointer to
+  // the real stack region.
+  size_t __asan_stack_malloc(size_t size, size_t real_stack)
+      __attribute__((visibility("default")));
+  void __asan_stack_free(size_t ptr, size_t size, size_t real_stack)
+      __attribute__((visibility("default")));
+
+  // Marks memory region [addr, addr+size) as unaddressable.
+  // This memory must be previously allocated by the user program. Accessing
+  // addresses in this region from instrumented code is forbidden until
+  // this region is unpoisoned. This function is not guaranteed to poison
+  // the whole region - it may poison only subregion of [addr, addr+size) due
+  // to ASan alignment restrictions.
+  // Method is NOT thread-safe in the sense that no two threads can
+  // (un)poison memory in the same memory region simultaneously.
+  void __asan_poison_memory_region(void const volatile *addr, size_t size);
+  // Marks memory region [addr, addr+size) as addressable.
+  // This memory must be previously allocated by the user program. Accessing
+  // addresses in this region is allowed until this region is poisoned again.
+  // This function may unpoison a superregion of [addr, addr+size) due to
+  // ASan alignment restrictions.
+  // Method is NOT thread-safe in the sense that no two threads can
+  // (un)poison memory in the same memory region simultaneously.
+  void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+
+// User code should use macro instead of functions.
+#ifdef ADDRESS_SANITIZER
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+  __asan_poison_memory_region((addr), (size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+  __asan_unpoison_memory_region((addr), (size))
+#else
+#define ASAN_POISON_MEMORY_REGION(addr, size) \
+  ((void)(addr), (void)(size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
+  ((void)(addr), (void)(size))
+#endif
+
+  // Returns true iff addr is poisoned (i.e. 1-byte read/write access to this
+  // address will result in error report from AddressSanitizer).
+  bool __asan_address_is_poisoned(void const volatile *addr);
+
+  // This is an internal function that is called to report an error.
+  // However it is still a part of the interface because users may want to
+  // set a breakpoint on this function in a debugger.
+  void __asan_report_error(uintptr_t pc, uintptr_t bp, uintptr_t sp,
+                           uintptr_t addr, bool is_write, size_t access_size)
+    __attribute__((visibility("default")));
+
+  // Sets the exit code to use when reporting an error.
+  // Returns the old value.
+  int __asan_set_error_exit_code(int exit_code);
+
+  // Returns the estimated number of bytes that will be reserved by allocator
+  // for request of "size" bytes. If ASan allocator can't allocate that much
+  // memory, returns the maximal possible allocation size, otherwise returns
+  // "size".
+  size_t __asan_get_estimated_allocated_size(size_t size);
+  // Returns true if p is NULL or if p was returned by the ASan allocator and
+  // is not yet freed.
+  bool __asan_get_ownership(const void *p);
+  // Returns the number of bytes reserved for the pointer p.
+  // Requires (get_ownership(p) == true).
+  size_t __asan_get_allocated_size(const void *p);
+  // Number of bytes, allocated and not yet freed by the application.
+  size_t __asan_get_current_allocated_bytes();
+  // Number of bytes, mmaped by asan allocator to fulfill allocation requests.
+  // Generally, for request of X bytes, allocator can reserve and add to free
+  // lists a large number of chunks of size X to use them for future requests.
+  // All these chunks count toward the heap size. Currently, allocator never
+  // releases memory to OS (instead, it just puts freed chunks to free lists).
+  size_t __asan_get_heap_size();
+  // Number of bytes, mmaped by asan allocator, which can be used to fulfill
+  // allocation requests. When a user program frees memory chunk, it can first
+  // fall into quarantine and will count toward __asan_get_free_bytes() later.
+  size_t __asan_get_free_bytes();
+  // Number of bytes in unmapped pages, that are released to OS. Currently,
+  // always returns 0.
+  size_t __asan_get_unmapped_bytes();
+  // Turns on/off statistics update. Returns the previous value.
+  bool __asan_enable_statistics(bool enable);
+  // Prints accumulated stats to stderr. Used for debugging.
+  void __asan_print_accumulated_stats();
+}  // namespace
+
+#endif  // ASAN_INTERFACE_H

Added: compiler-rt/trunk/lib/asan/asan_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_internal.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_internal.h (added)
+++ compiler-rt/trunk/lib/asan/asan_internal.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,178 @@
+//===-- asan_internal.h -----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header which defines various general utilities.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_INTERNAL_H
+#define ASAN_INTERNAL_H
+
+#include <stdint.h>  // for __WORDSIZE
+#include <stdlib.h>  // for size_t
+#include <unistd.h>  // for _exit
+
+#ifdef ANDROID
+#include <sys/atomics.h>
+#endif
+
+#ifdef ADDRESS_SANITIZER
+# error "The AddressSanitizer run-time should not be"
+        " instrumented by AddressSanitizer"
+#endif
+
+// All internal functions in asan reside inside the __asan namespace
+// to avoid namespace collisions with the user programs.
+// Seperate namespace also makes it simpler to distinguish the asan run-time
+// functions from the instrumented user code in a profile.
+namespace __asan {
+
+class AsanThread;
+struct AsanStackTrace;
+
+//  asan_rtl.cc
+void CheckFailed(const char *cond, const char *file, int line);
+void ShowStatsAndAbort();
+
+//  asan_globals.cc
+bool DescribeAddrIfGlobal(uintptr_t addr);
+
+//  asan_malloc_linux.cc / asan_malloc_mac.cc
+void ReplaceSystemMalloc();
+
+//  asan_linux.cc / asan_mac.cc
+void *AsanDoesNotSupportStaticLinkage();
+void *asan_mmap(void *addr, size_t length, int prot, int flags,
+                int fd, uint64_t offset);
+ssize_t asan_write(int fd, const void *buf, size_t count);
+
+//  asan_printf.cc
+void RawWrite(const char *buffer);
+int SNPrint(char *buffer, size_t length, const char *format, ...);
+void Printf(const char *format, ...);
+void Report(const char *format, ...);
+
+extern size_t FLAG_quarantine_size;
+extern int    FLAG_demangle;
+extern bool   FLAG_symbolize;
+extern int    FLAG_v;
+extern bool   FLAG_mt;
+extern size_t FLAG_redzone;
+extern int    FLAG_debug;
+extern bool   FLAG_poison_shadow;
+extern int    FLAG_report_globals;
+extern size_t FLAG_malloc_context_size;
+extern bool   FLAG_stats;
+extern bool   FLAG_replace_str;
+extern bool   FLAG_replace_intrin;
+extern bool   FLAG_replace_cfallocator;
+extern bool   FLAG_fast_unwind;
+extern bool   FLAG_use_fake_stack;
+extern size_t FLAG_max_malloc_fill_size;
+extern int    FLAG_exitcode;
+extern bool   FLAG_allow_user_poisoning;
+
+extern int asan_inited;
+// Used to avoid infinite recursion in __asan_init().
+extern bool asan_init_is_running;
+
+enum LinkerInitialized { LINKER_INITIALIZED = 0 };
+
+#ifndef ASAN_DIE
+#define ASAN_DIE _exit(FLAG_exitcode)
+#endif  // ASAN_DIE
+
+#define CHECK(cond) do { if (!(cond)) { \
+  CheckFailed(#cond, __FILE__, __LINE__); \
+}}while(0)
+
+#define RAW_CHECK_MSG(expr, msg) do { \
+  if (!(expr)) { \
+    RawWrite(msg); \
+    ASAN_DIE; \
+  } \
+} while (0)
+
+#define RAW_CHECK(expr) RAW_CHECK_MSG(expr, #expr)
+
+#define UNIMPLEMENTED() CHECK("unimplemented" && 0)
+
+#define ASAN_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+const size_t kWordSize = __WORDSIZE / 8;
+const size_t kWordSizeInBits = 8 * kWordSize;
+const size_t kPageSizeBits = 12;
+const size_t kPageSize = 1UL << kPageSizeBits;
+
+#define GET_CALLER_PC() (uintptr_t)__builtin_return_address(0)
+#define GET_CURRENT_FRAME() (uintptr_t)__builtin_frame_address(0)
+
+#define GET_BP_PC_SP \
+  uintptr_t bp = GET_CURRENT_FRAME();              \
+  uintptr_t pc = GET_CALLER_PC();                  \
+  uintptr_t local_stack;                           \
+  uintptr_t sp = (uintptr_t)&local_stack;
+
+// These magic values are written to shadow for better error reporting.
+const int kAsanHeapLeftRedzoneMagic = 0xfa;
+const int kAsanHeapRightRedzoneMagic = 0xfb;
+const int kAsanHeapFreeMagic = 0xfd;
+const int kAsanStackLeftRedzoneMagic = 0xf1;
+const int kAsanStackMidRedzoneMagic = 0xf2;
+const int kAsanStackRightRedzoneMagic = 0xf3;
+const int kAsanStackPartialRedzoneMagic = 0xf4;
+const int kAsanStackAfterReturnMagic = 0xf5;
+const int kAsanUserPoisonedMemoryMagic = 0xf7;
+const int kAsanGlobalRedzoneMagic = 0xf9;
+
+static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3;
+static const uintptr_t kRetiredStackFrameMagic = 0x45E0360E;
+
+// Poison the shadow memory which corresponds to 'redzone_size' bytes
+// of the original memory, where first 'size' bytes are addressable.
+static inline void
+PoisonShadowPartialRightRedzone(unsigned char *shadow,
+                                uintptr_t size,
+                                uintptr_t redzone_size,
+                                uintptr_t shadow_granularity,
+                                unsigned char magic) {
+  for (uintptr_t i = 0; i < redzone_size;
+       i+= shadow_granularity, shadow++) {
+    if (i + shadow_granularity <= size) {
+      *shadow = 0;  // fully addressable
+    } else if (i >= size) {
+      *shadow = (shadow_granularity == 128) ? 0xff : magic;  // unaddressable
+    } else {
+      *shadow = size - i;  // first size-i bytes are addressable
+    }
+  }
+}
+
+// -------------------------- Atomic ---------------- {{{1
+static inline int AtomicInc(int *a) {
+  if (!FLAG_mt) return ++(*a);
+#ifdef ANDROID
+  return __atomic_inc(a) + 1;
+#else
+  return __sync_add_and_fetch(a, 1);
+#endif
+}
+
+static inline int AtomicDec(int *a) {
+  if (!FLAG_mt) return --(*a);
+#ifdef ANDROID
+  return __atomic_dec(a) - 1;
+#else
+  return __sync_add_and_fetch(a, -1);
+#endif
+}
+
+}  // namespace __asan
+
+#endif  // ASAN_INTERNAL_H

Added: compiler-rt/trunk/lib/asan/asan_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_linux.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_linux.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_linux.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,48 @@
+//===-- asan_linux.cc -----------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "asan_internal.h"
+
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+extern char _DYNAMIC[];
+
+namespace __asan {
+
+void *AsanDoesNotSupportStaticLinkage() {
+  // This will fail to link with -static.
+  return &_DYNAMIC;
+}
+
+#ifdef ANDROID
+#define SYS_mmap2 __NR_mmap2
+#define SYS_write __NR_write
+#endif
+
+void *asan_mmap(void *addr, size_t length, int prot, int flags,
+                int fd, uint64_t offset) {
+# if __WORDSIZE == 64
+  return (void *)syscall(SYS_mmap, addr, length, prot, flags, fd, offset);
+# else
+  return (void *)syscall(SYS_mmap2, addr, length, prot, flags, fd, offset);
+# endif
+}
+
+ssize_t asan_write(int fd, const void *buf, size_t count) {
+  return (ssize_t)syscall(SYS_write, fd, buf, count);
+}
+
+}  // namespace __asan

Added: compiler-rt/trunk/lib/asan/asan_lock.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_lock.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_lock.h (added)
+++ compiler-rt/trunk/lib/asan/asan_lock.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,100 @@
+//===-- asan_lock.h ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// A wrapper for a simple lock.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_LOCK_H
+#define ASAN_LOCK_H
+
+#include "asan_internal.h"
+
+// The locks in ASan are global objects and they are never destroyed to avoid
+// at-exit races (that is, a lock is being used by other threads while the main
+// thread is doing atexit destructors).
+
+#ifdef __APPLE__
+#include <pthread.h>
+
+#include <libkern/OSAtomic.h>
+namespace __asan {
+class AsanLock {
+ public:
+  explicit AsanLock(LinkerInitialized) :
+    mu_(OS_SPINLOCK_INIT),
+    owner_(0),
+    is_locked_(false) {}
+
+  void Lock() {
+    CHECK(owner_ != pthread_self());
+    OSSpinLockLock(&mu_);
+    is_locked_ = true;
+    owner_ = pthread_self();
+  }
+  void Unlock() {
+    owner_ = 0;
+    is_locked_ = false;
+    OSSpinLockUnlock(&mu_);
+  }
+
+  bool IsLocked() {
+    // This is not atomic, e.g. one thread may get different values if another
+    // one is about to release the lock.
+    return is_locked_;
+  }
+ private:
+  OSSpinLock mu_;
+  volatile pthread_t owner_;  // for debugging purposes
+  bool is_locked_;  // for silly malloc_introspection_t interface
+};
+}  // namespace __asan
+
+#else  // assume linux
+#include <pthread.h>
+namespace __asan {
+class AsanLock {
+ public:
+  explicit AsanLock(LinkerInitialized) {
+    // We assume that pthread_mutex_t initialized to all zeroes is a valid
+    // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
+    // a gcc warning:
+    // extended initializer lists only available with -std=c++0x or -std=gnu++0x
+  }
+  void Lock() {
+    pthread_mutex_lock(&mu_);
+    // pthread_spin_lock(&mu_);
+  }
+  void Unlock() {
+    pthread_mutex_unlock(&mu_);
+    // pthread_spin_unlock(&mu_);
+  }
+ private:
+  pthread_mutex_t mu_;
+  // pthread_spinlock_t mu_;
+};
+}  // namespace __asan
+#endif
+
+namespace __asan {
+class ScopedLock {
+ public:
+  explicit ScopedLock(AsanLock *mu) : mu_(mu) {
+    mu_->Lock();
+  }
+  ~ScopedLock() {
+    mu_->Unlock();
+  }
+ private:
+  AsanLock *mu_;
+};
+
+}  // namespace __asan
+
+#endif  // ASAN_LOCK_H

Added: compiler-rt/trunk/lib/asan/asan_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_mac.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_mac.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_mac.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,256 @@
+//===-- asan_mac.cc -------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific details.
+//===----------------------------------------------------------------------===//
+
+#ifndef __APPLE__
+#error "This file should be used on Mac OS X only."
+#endif
+
+#include "asan_mac.h"
+
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "asan_thread_registry.h"
+
+#include <algorithm>
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+namespace __asan {
+
+extern dispatch_async_f_f real_dispatch_async_f;
+extern dispatch_sync_f_f real_dispatch_sync_f;
+extern dispatch_after_f_f real_dispatch_after_f;
+extern dispatch_barrier_async_f_f real_dispatch_barrier_async_f;
+extern dispatch_group_async_f_f real_dispatch_group_async_f;
+extern pthread_workqueue_additem_np_f real_pthread_workqueue_additem_np;
+
+// No-op. Mac does not support static linkage anyway.
+void *AsanDoesNotSupportStaticLinkage() {
+  return NULL;
+}
+
+void *asan_mmap(void *addr, size_t length, int prot, int flags,
+                int fd, uint64_t offset) {
+  return mmap(addr, length, prot, flags, fd, offset);
+}
+
+ssize_t asan_write(int fd, const void *buf, size_t count) {
+  return write(fd, buf, count);
+}
+
+// Support for the following functions from libdispatch on Mac OS:
+//   dispatch_async_f()
+//   dispatch_async()
+//   dispatch_sync_f()
+//   dispatch_sync()
+//   dispatch_after_f()
+//   dispatch_after()
+//   dispatch_group_async_f()
+//   dispatch_group_async()
+// TODO(glider): libdispatch API contains other functions that we don't support
+// yet.
+//
+// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
+// they can cause jobs to run on a thread different from the current one.
+// TODO(glider): if so, we need a test for this (otherwise we should remove
+// them).
+//
+// The following functions use dispatch_barrier_async_f() (which isn't a library
+// function but is exported) and are thus supported:
+//   dispatch_source_set_cancel_handler_f()
+//   dispatch_source_set_cancel_handler()
+//   dispatch_source_set_event_handler_f()
+//   dispatch_source_set_event_handler()
+//
+// The reference manual for Grand Central Dispatch is available at
+//   http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// The implementation details are at
+//   http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
+
+extern "C"
+void asan_dispatch_call_block_and_release(void *block) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_block_context_t *context = (asan_block_context_t*)block;
+  if (FLAG_v >= 2) {
+    Report("asan_dispatch_call_block_and_release(): "
+           "context: %p, pthread_self: %p\n",
+           block, pthread_self());
+  }
+  AsanThread *t = asanThreadRegistry().GetCurrent();
+  if (t) {
+    // We've already executed a job on this worker thread. Let's reuse the
+    // AsanThread object.
+    if (t != asanThreadRegistry().GetMain()) {
+      // Flush the statistics and update the current thread's tid.
+      asanThreadRegistry().UnregisterThread(t);
+      asanThreadRegistry().RegisterThread(t, context->parent_tid, &stack);
+    }
+    // Otherwise the worker is being executed on the main thread -- we are
+    // draining the dispatch queue.
+    // TODO(glider): any checks for that?
+  } else {
+    // It's incorrect to assert that the current thread is not dying: at least
+    // the callbacks from dispatch_sync() are sometimes called after the TSD is
+    // destroyed.
+    t = (AsanThread*)asan_malloc(sizeof(AsanThread), &stack);
+    new(t) AsanThread(context->parent_tid,
+                      /*start_routine*/NULL, /*arg*/NULL, &stack);
+    asanThreadRegistry().SetCurrent(t);
+  }
+  // Call the original dispatcher for the block.
+  context->func(context->block);
+  asan_free(context, &stack);
+}
+
+}  // namespace __asan
+
+using namespace __asan;  // NOLINT
+
+// Wrap |ctxt| and |func| into an asan_block_context_t.
+// The caller retains control of the allocated context.
+extern "C"
+asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func,
+                                         AsanStackTrace *stack) {
+  asan_block_context_t *asan_ctxt =
+      (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack);
+  asan_ctxt->block = ctxt;
+  asan_ctxt->func = func;
+  AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+  if (FLAG_debug) {
+    // Sometimes at Chromium teardown this assertion is violated:
+    //  -- a task is created via dispatch_async() on the "CFMachPort"
+    //     thread while doing _dispatch_queue_drain();
+    //  -- a task is created via dispatch_async_f() on the
+    //     "com.apple.root.default-overcommit-priority" thread while doing
+    //     _dispatch_dispose().
+    // TODO(glider): find out what's going on.
+    CHECK(curr_thread || asanThreadRegistry().IsCurrentThreadDying());
+  }
+  asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrMinusOne();
+  return asan_ctxt;
+}
+
+// TODO(glider): can we reduce code duplication by introducing a macro?
+extern "C"
+int WRAP(dispatch_async_f)(dispatch_queue_t dq,
+                           void *ctxt,
+                           dispatch_function_t func) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+  if (FLAG_v >= 2) {
+    Report("dispatch_async_f(): context: %p, pthread_self: %p\n",
+        asan_ctxt, pthread_self());
+    PRINT_CURRENT_STACK();
+  }
+  return real_dispatch_async_f(dq, (void*)asan_ctxt,
+                               asan_dispatch_call_block_and_release);
+}
+
+extern "C"
+int WRAP(dispatch_sync_f)(dispatch_queue_t dq,
+                          void *ctxt,
+                          dispatch_function_t func) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+  if (FLAG_v >= 2) {
+    Report("dispatch_sync_f(): context: %p, pthread_self: %p\n",
+        asan_ctxt, pthread_self());
+    PRINT_CURRENT_STACK();
+  }
+  return real_dispatch_sync_f(dq, (void*)asan_ctxt,
+                              asan_dispatch_call_block_and_release);
+}
+
+extern "C"
+int WRAP(dispatch_after_f)(dispatch_time_t when,
+                           dispatch_queue_t dq,
+                           void *ctxt,
+                           dispatch_function_t func) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+  if (FLAG_v >= 2) {
+    Report("dispatch_after_f: %p\n", asan_ctxt);
+    PRINT_CURRENT_STACK();
+  }
+  return real_dispatch_after_f(when, dq, (void*)asan_ctxt,
+                               asan_dispatch_call_block_and_release);
+}
+
+extern "C"
+void WRAP(dispatch_barrier_async_f)(dispatch_queue_t dq,
+                                    void *ctxt, dispatch_function_t func) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+  if (FLAG_v >= 2) {
+    Report("dispatch_barrier_async_f(): context: %p, pthread_self: %p\n",
+           asan_ctxt, pthread_self());
+    PRINT_CURRENT_STACK();
+  }
+  real_dispatch_barrier_async_f(dq, (void*)asan_ctxt,
+                                asan_dispatch_call_block_and_release);
+}
+
+extern "C"
+void WRAP(dispatch_group_async_f)(dispatch_group_t group,
+                                  dispatch_queue_t dq,
+                                  void *ctxt, dispatch_function_t func) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack);
+  if (FLAG_v >= 2) {
+    Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n",
+           asan_ctxt, pthread_self());
+    PRINT_CURRENT_STACK();
+  }
+  real_dispatch_group_async_f(group, dq, (void*)asan_ctxt,
+                              asan_dispatch_call_block_and_release);
+}
+
+// The following stuff has been extremely helpful while looking for the
+// unhandled functions that spawned jobs on Chromium shutdown. If the verbosity
+// level is 2 or greater, we wrap pthread_workqueue_additem_np() in order to
+// find the points of worker thread creation (each of such threads may be used
+// to run several tasks, that's why this is not enough to support the whole
+// libdispatch API.
+extern "C"
+void *wrap_workitem_func(void *arg) {
+  if (FLAG_v >= 2) {
+    Report("wrap_workitem_func: %p, pthread_self: %p\n", arg, pthread_self());
+  }
+  asan_block_context_t *ctxt = (asan_block_context_t*)arg;
+  worker_t fn = (worker_t)(ctxt->func);
+  void *result =  fn(ctxt->block);
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_free(arg, &stack);
+  return result;
+}
+
+extern "C"
+int WRAP(pthread_workqueue_additem_np)(pthread_workqueue_t workq,
+    void *(*workitem_func)(void *), void * workitem_arg,
+    pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  asan_block_context_t *asan_ctxt =
+      (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), &stack);
+  asan_ctxt->block = workitem_arg;
+  asan_ctxt->func = (dispatch_function_t)workitem_func;
+  asan_ctxt->parent_tid = asanThreadRegistry().GetCurrentTidOrMinusOne();
+  if (FLAG_v >= 2) {
+    Report("pthread_workqueue_additem_np: %p\n", asan_ctxt);
+    PRINT_CURRENT_STACK();
+  }
+  return real_pthread_workqueue_additem_np(workq, wrap_workitem_func, asan_ctxt,
+                                           itemhandlep, gencountp);
+}

Added: compiler-rt/trunk/lib/asan/asan_mac.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_mac.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_mac.h (added)
+++ compiler-rt/trunk/lib/asan/asan_mac.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,83 @@
+//===-- asan_mac.h ----------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_mac.cc
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_MAC_H
+#define ASAN_MAC_H
+
+#include "asan_interceptors.h"
+
+// TODO(glider): need to check if the OS X version is 10.6 or greater.
+#include <dispatch/dispatch.h>
+#include <setjmp.h>
+
+typedef void* pthread_workqueue_t;
+typedef void* pthread_workitem_handle_t;
+
+typedef void (*dispatch_function_t)(void *block);
+typedef void* (*worker_t)(void *block);
+typedef int (*dispatch_async_f_f)(dispatch_queue_t dq, void *ctxt,
+                                  dispatch_function_t func);
+typedef int (*dispatch_sync_f_f)(dispatch_queue_t dq, void *ctxt,
+                                  dispatch_function_t func);
+typedef int (*dispatch_after_f_f)(dispatch_time_t when,
+                                  dispatch_queue_t dq, void *ctxt,
+                                  dispatch_function_t func);
+typedef void (*dispatch_barrier_async_f_f)(dispatch_queue_t dq,
+                                           void *ctxt,
+                                           dispatch_function_t func);
+typedef void (*dispatch_group_async_f_f)(dispatch_group_t group,
+                                         dispatch_queue_t dq,
+                                         void *ctxt, dispatch_function_t func);
+typedef int (*pthread_workqueue_additem_np_f)(pthread_workqueue_t workq,
+    void *(*workitem_func)(void *), void * workitem_arg,
+    pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp);
+
+
+// A wrapper for the ObjC blocks used to support libdispatch.
+typedef struct {
+  void *block;
+  dispatch_function_t func;
+  int parent_tid;
+} asan_block_context_t;
+
+
+extern "C" {
+// dispatch_barrier_async_f() is not declared in <dispatch/dispatch.h>.
+void dispatch_barrier_async_f(dispatch_queue_t dq,
+                              void *ctxt, dispatch_function_t func);
+// Neither is pthread_workqueue_additem_np().
+int pthread_workqueue_additem_np(pthread_workqueue_t workq,
+    void *(*workitem_func)(void *), void * workitem_arg,
+    pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp);
+
+int WRAP(dispatch_async_f)(dispatch_queue_t dq,
+                           void *ctxt,
+                           dispatch_function_t func);
+int WRAP(dispatch_sync_f)(dispatch_queue_t dq,
+                          void *ctxt,
+                          dispatch_function_t func);
+int WRAP(dispatch_after_f)(dispatch_time_t when,
+                           dispatch_queue_t dq,
+                           void *ctxt,
+                           dispatch_function_t func);
+void WRAP(dispatch_barrier_async_f)(dispatch_queue_t dq,
+                                    void *ctxt, dispatch_function_t func);
+void WRAP(dispatch_group_async_f)(dispatch_group_t group,
+                                  dispatch_queue_t dq,
+                                  void *ctxt, dispatch_function_t func);
+int WRAP(pthread_workqueue_additem_np)(pthread_workqueue_t workq,
+    void *(*workitem_func)(void *), void * workitem_arg,
+    pthread_workitem_handle_t * itemhandlep, unsigned int *gencountp);
+}
+
+#endif  // ASAN_MAC_H

Added: compiler-rt/trunk/lib/asan/asan_malloc_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_malloc_linux.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_malloc_linux.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_malloc_linux.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,139 @@
+//===-- asan_malloc_linux.cc ------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Linux-specific malloc interception.
+// We simply define functions like malloc, free, realloc, etc.
+// They will replace the corresponding libc functions automagically.
+//===----------------------------------------------------------------------===//
+
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+
+#include <malloc.h>
+
+#define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+
+#ifdef ANDROID
+struct MallocDebug {
+  void* (*malloc)(size_t bytes);
+  void  (*free)(void* mem);
+  void* (*calloc)(size_t n_elements, size_t elem_size);
+  void* (*realloc)(void* oldMem, size_t bytes);
+  void* (*memalign)(size_t alignment, size_t bytes);
+};
+
+const MallocDebug asan_malloc_dispatch __attribute__((aligned(32))) = {
+  malloc, free, calloc, realloc, memalign
+};
+
+extern "C" const MallocDebug* __libc_malloc_dispatch;
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+  __libc_malloc_dispatch = &asan_malloc_dispatch;
+}
+}  // namespace __asan
+
+#else  // ANDROID
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+}
+}  // namespace __asan
+#endif  // ANDROID
+
+// ---------------------- Replacement functions ---------------- {{{1
+using namespace __asan;  // NOLINT
+
+extern "C" {
+INTERCEPTOR_ATTRIBUTE
+void free(void *ptr) {
+  GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+  asan_free(ptr, &stack);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void cfree(void *ptr) {
+  GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+  asan_free(ptr, &stack);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void *malloc(size_t size) {
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_malloc(size, &stack);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void *calloc(size_t nmemb, size_t size) {
+  if (!asan_inited) {
+    // Hack: dlsym calls calloc before real_calloc is retrieved from dlsym.
+    const size_t kCallocPoolSize = 1024;
+    static uintptr_t calloc_memory_for_dlsym[kCallocPoolSize];
+    static size_t allocated;
+    size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+    void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+    allocated += size_in_words;
+    CHECK(allocated < kCallocPoolSize);
+    return mem;
+  }
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_calloc(nmemb, size, &stack);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void *realloc(void *ptr, size_t size) {
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_realloc(ptr, size, &stack);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void *memalign(size_t boundary, size_t size) {
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_memalign(boundary, size, &stack);
+}
+
+void* __libc_memalign(size_t align, size_t s)
+  __attribute__((alias("memalign")));
+
+INTERCEPTOR_ATTRIBUTE
+struct mallinfo mallinfo() {
+  struct mallinfo res;
+  real_memset(&res, 0, sizeof(res));
+  return res;
+}
+
+INTERCEPTOR_ATTRIBUTE
+int mallopt(int cmd, int value) {
+  return -1;
+}
+
+INTERCEPTOR_ATTRIBUTE
+int posix_memalign(void **memptr, size_t alignment, size_t size) {
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  // Printf("posix_memalign: %lx %ld\n", alignment, size);
+  return asan_posix_memalign(memptr, alignment, size, &stack);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void *valloc(size_t size) {
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_valloc(size, &stack);
+}
+
+INTERCEPTOR_ATTRIBUTE
+void *pvalloc(size_t size) {
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_pvalloc(size, &stack);
+}
+}  // extern "C"

Added: compiler-rt/trunk/lib/asan/asan_malloc_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_malloc_mac.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_malloc_mac.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_malloc_mac.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,380 @@
+//===-- asan_rtl.cc ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Mac-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include <AvailabilityMacros.h>
+#include <CoreFoundation/CFBase.h>
+#include <malloc/malloc.h>
+#include <setjmp.h>
+
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+
+// Similar code is used in Google Perftools,
+// http://code.google.com/p/google-perftools.
+
+// ---------------------- Replacement functions ---------------- {{{1
+using namespace __asan;  // NOLINT
+
+// The free() implementation provided by OS X calls malloc_zone_from_ptr()
+// to find the owner of |ptr|. If the result is NULL, an invalid free() is
+// reported. Our implementation falls back to asan_free() in this case
+// in order to print an ASan-style report.
+extern "C"
+void free(void *ptr) {
+  malloc_zone_t *zone = malloc_zone_from_ptr(ptr);
+  if (zone) {
+#if defined(MAC_OS_X_VERSION_10_6) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+    if ((zone->version >= 6) && (zone->free_definite_size)) {
+      zone->free_definite_size(zone, ptr, malloc_size(ptr));
+    } else {
+      malloc_zone_free(zone, ptr);
+    }
+#else
+    malloc_zone_free(zone, ptr);
+#endif
+  } else {
+    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+    asan_free(ptr, &stack);
+  }
+}
+
+// TODO(glider): do we need both zones?
+static malloc_zone_t *system_malloc_zone = NULL;
+static malloc_zone_t *system_purgeable_zone = NULL;
+
+// We need to provide wrappers around all the libc functions.
+namespace {
+// TODO(glider): the mz_* functions should be united with the Linux wrappers,
+// as they are basically copied from there.
+size_t mz_size(malloc_zone_t* zone, const void* ptr) {
+  // Fast path: check whether this pointer belongs to the original malloc zone.
+  // We cannot just call malloc_zone_from_ptr(), because it in turn
+  // calls our mz_size().
+  if (system_malloc_zone) {
+    if ((system_malloc_zone->size)(system_malloc_zone, ptr)) return 0;
+  }
+  return __asan_mz_size(ptr);
+}
+
+void *mz_malloc(malloc_zone_t *zone, size_t size) {
+  if (!asan_inited) {
+    CHECK(system_malloc_zone);
+    return malloc_zone_malloc(system_malloc_zone, size);
+  }
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_malloc(size, &stack);
+}
+
+void *cf_malloc(CFIndex size, CFOptionFlags hint, void *info) {
+  if (!asan_inited) {
+    CHECK(system_malloc_zone);
+    return malloc_zone_malloc(system_malloc_zone, size);
+  }
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_malloc(size, &stack);
+}
+
+void *mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) {
+  if (!asan_inited) {
+    // Hack: dlsym calls calloc before real_calloc is retrieved from dlsym.
+    const size_t kCallocPoolSize = 1024;
+    static uintptr_t calloc_memory_for_dlsym[kCallocPoolSize];
+    static size_t allocated;
+    size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize;
+    void *mem = (void*)&calloc_memory_for_dlsym[allocated];
+    allocated += size_in_words;
+    CHECK(allocated < kCallocPoolSize);
+    return mem;
+  }
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_calloc(nmemb, size, &stack);
+}
+
+void *mz_valloc(malloc_zone_t *zone, size_t size) {
+  if (!asan_inited) {
+    CHECK(system_malloc_zone);
+    return malloc_zone_valloc(system_malloc_zone, size);
+  }
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_memalign(kPageSize, size, &stack);
+}
+
+void print_zone_for_ptr(void *ptr) {
+  malloc_zone_t *orig_zone = malloc_zone_from_ptr(ptr);
+  if (orig_zone) {
+    if (orig_zone->zone_name) {
+      Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
+             ptr, orig_zone, orig_zone->zone_name);
+    } else {
+      Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
+             ptr, orig_zone);
+    }
+  } else {
+    Printf("malloc_zone_from_ptr(%p) = NULL\n", ptr);
+  }
+}
+
+// TODO(glider): the allocation callbacks need to be refactored.
+void mz_free(malloc_zone_t *zone, void *ptr) {
+  if (!ptr) return;
+  malloc_zone_t *orig_zone = malloc_zone_from_ptr(ptr);
+  // For some reason Chromium calls mz_free() for pointers that belong to
+  // DefaultPurgeableMallocZone instead of asan_zone. We might want to
+  // fix this someday.
+  if (orig_zone == system_purgeable_zone) {
+    system_purgeable_zone->free(system_purgeable_zone, ptr);
+    return;
+  }
+  if (__asan_mz_size(ptr)) {
+    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+    asan_free(ptr, &stack);
+  } else {
+    // Let us just leak this memory for now.
+    Printf("mz_free(%p) -- attempting to free unallocated memory.\n"
+           "AddressSanitizer is ignoring this error on Mac OS now.\n", ptr);
+    print_zone_for_ptr(ptr);
+    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+    stack.PrintStack();
+    return;
+  }
+}
+
+void cf_free(void *ptr, void *info) {
+  if (!ptr) return;
+  malloc_zone_t *orig_zone = malloc_zone_from_ptr(ptr);
+  // For some reason Chromium calls mz_free() for pointers that belong to
+  // DefaultPurgeableMallocZone instead of asan_zone. We might want to
+  // fix this someday.
+  if (orig_zone == system_purgeable_zone) {
+    system_purgeable_zone->free(system_purgeable_zone, ptr);
+    return;
+  }
+  if (__asan_mz_size(ptr)) {
+    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+    asan_free(ptr, &stack);
+  } else {
+    // Let us just leak this memory for now.
+    Printf("cf_free(%p) -- attempting to free unallocated memory.\n"
+           "AddressSanitizer is ignoring this error on Mac OS now.\n", ptr);
+    print_zone_for_ptr(ptr);
+    GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+    stack.PrintStack();
+    return;
+  }
+}
+
+void *mz_realloc(malloc_zone_t *zone, void *ptr, size_t size) {
+  if (!ptr) {
+    GET_STACK_TRACE_HERE_FOR_MALLOC;
+    return asan_malloc(size, &stack);
+  } else {
+    if (__asan_mz_size(ptr)) {
+      GET_STACK_TRACE_HERE_FOR_MALLOC;
+      return asan_realloc(ptr, size, &stack);
+    } else {
+      // We can't recover from reallocating an unknown address, because
+      // this would require reading at most |size| bytes from
+      // potentially unaccessible memory.
+      Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
+             "This is an unrecoverable problem, exiting now.\n", ptr);
+      print_zone_for_ptr(ptr);
+      GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+      stack.PrintStack();
+      ShowStatsAndAbort();
+      return NULL;  // unreachable
+    }
+  }
+}
+
+void *cf_realloc(void *ptr, CFIndex size, CFOptionFlags hint, void *info) {
+  if (!ptr) {
+    GET_STACK_TRACE_HERE_FOR_MALLOC;
+    return asan_malloc(size, &stack);
+  } else {
+    if (__asan_mz_size(ptr)) {
+      GET_STACK_TRACE_HERE_FOR_MALLOC;
+      return asan_realloc(ptr, size, &stack);
+    } else {
+      // We can't recover from reallocating an unknown address, because
+      // this would require reading at most |size| bytes from
+      // potentially unaccessible memory.
+      Printf("cf_realloc(%p) -- attempting to realloc unallocated memory.\n"
+             "This is an unrecoverable problem, exiting now.\n", ptr);
+      print_zone_for_ptr(ptr);
+      GET_STACK_TRACE_HERE_FOR_FREE(ptr);
+      stack.PrintStack();
+      ShowStatsAndAbort();
+      return NULL;  // unreachable
+    }
+  }
+}
+
+void mz_destroy(malloc_zone_t* zone) {
+  // A no-op -- we will not be destroyed!
+  Printf("mz_destroy() called -- ignoring\n");
+}
+  // from AvailabilityMacros.h
+#if defined(MAC_OS_X_VERSION_10_6) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+void *mz_memalign(malloc_zone_t *zone, size_t align, size_t size) {
+  if (!asan_inited) {
+    CHECK(system_malloc_zone);
+    return malloc_zone_memalign(system_malloc_zone, align, size);
+  }
+  GET_STACK_TRACE_HERE_FOR_MALLOC;
+  return asan_memalign(align, size, &stack);
+}
+
+void mz_free_definite_size(malloc_zone_t* zone, void *ptr, size_t size) {
+  // TODO(glider): check that |size| is valid.
+  UNIMPLEMENTED();
+}
+#endif
+
+// malloc_introspection callbacks.  I'm not clear on what all of these do.
+kern_return_t mi_enumerator(task_t task, void *,
+                            unsigned type_mask, vm_address_t zone_address,
+                            memory_reader_t reader,
+                            vm_range_recorder_t recorder) {
+  // Should enumerate all the pointers we have.  Seems like a lot of work.
+  return KERN_FAILURE;
+}
+
+size_t mi_good_size(malloc_zone_t *zone, size_t size) {
+  // I think it's always safe to return size, but we maybe could do better.
+  return size;
+}
+
+boolean_t mi_check(malloc_zone_t *zone) {
+  UNIMPLEMENTED();
+  return true;
+}
+
+void mi_print(malloc_zone_t *zone, boolean_t verbose) {
+  UNIMPLEMENTED();
+  return;
+}
+
+void mi_log(malloc_zone_t *zone, void *address) {
+  // I don't think we support anything like this
+}
+
+void mi_force_lock(malloc_zone_t *zone) {
+  __asan_mz_force_lock();
+}
+
+void mi_force_unlock(malloc_zone_t *zone) {
+  __asan_mz_force_unlock();
+}
+
+void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) {
+  // TODO(csilvers): figure out how to fill these out
+  // TODO(glider): port this from tcmalloc when ready.
+  stats->blocks_in_use = 0;
+  stats->size_in_use = 0;
+  stats->max_size_in_use = 0;
+  stats->size_allocated = 0;
+}
+
+boolean_t mi_zone_locked(malloc_zone_t *zone) {
+  // UNIMPLEMENTED();
+  return false;
+}
+
+}  // unnamed namespace
+
+extern bool kCFUseCollectableAllocator;  // is GC on?
+
+namespace __asan {
+void ReplaceSystemMalloc() {
+  static malloc_introspection_t asan_introspection;
+  __asan::real_memset(&asan_introspection, 0, sizeof(asan_introspection));
+
+  asan_introspection.enumerator = &mi_enumerator;
+  asan_introspection.good_size = &mi_good_size;
+  asan_introspection.check = &mi_check;
+  asan_introspection.print = &mi_print;
+  asan_introspection.log = &mi_log;
+  asan_introspection.force_lock = &mi_force_lock;
+  asan_introspection.force_unlock = &mi_force_unlock;
+
+  static malloc_zone_t asan_zone;
+  __asan::real_memset(&asan_zone, 0, sizeof(malloc_zone_t));
+
+  // Start with a version 4 zone which is used for OS X 10.4 and 10.5.
+  asan_zone.version = 4;
+  asan_zone.zone_name = "asan";
+  asan_zone.size = &mz_size;
+  asan_zone.malloc = &mz_malloc;
+  asan_zone.calloc = &mz_calloc;
+  asan_zone.valloc = &mz_valloc;
+  asan_zone.free = &mz_free;
+  asan_zone.realloc = &mz_realloc;
+  asan_zone.destroy = &mz_destroy;
+  asan_zone.batch_malloc = NULL;
+  asan_zone.batch_free = NULL;
+  asan_zone.introspect = &asan_introspection;
+
+  // from AvailabilityMacros.h
+#if defined(MAC_OS_X_VERSION_10_6) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+  // Switch to version 6 on OSX 10.6 to support memalign.
+  asan_zone.version = 6;
+  asan_zone.free_definite_size = 0;
+  asan_zone.memalign = &mz_memalign;
+  asan_introspection.zone_locked = &mi_zone_locked;
+
+  // Request the default purgable zone to force its creation. The
+  // current default zone is registered with the purgable zone for
+  // doing tiny and small allocs.  Sadly, it assumes that the default
+  // zone is the szone implementation from OS X and will crash if it
+  // isn't.  By creating the zone now, this will be true and changing
+  // the default zone won't cause a problem.  (OS X 10.6 and higher.)
+  system_purgeable_zone = malloc_default_purgeable_zone();
+#endif
+
+  // Register the ASan zone. At this point, it will not be the
+  // default zone.
+  malloc_zone_register(&asan_zone);
+
+  // Unregister and reregister the default zone.  Unregistering swaps
+  // the specified zone with the last one registered which for the
+  // default zone makes the more recently registered zone the default
+  // zone.  The default zone is then re-registered to ensure that
+  // allocations made from it earlier will be handled correctly.
+  // Things are not guaranteed to work that way, but it's how they work now.
+  system_malloc_zone = malloc_default_zone();
+  malloc_zone_unregister(system_malloc_zone);
+  malloc_zone_register(system_malloc_zone);
+  // Make sure the default allocator was replaced.
+  CHECK(malloc_default_zone() == &asan_zone);
+
+  if (FLAG_replace_cfallocator) {
+    static CFAllocatorContext asan_context =
+        { /*version*/ 0, /*info*/ &asan_zone,
+          /*retain*/ NULL, /*release*/ NULL,
+          /*copyDescription*/NULL,
+          /*allocate*/ &cf_malloc,
+          /*reallocate*/ &cf_realloc,
+          /*deallocate*/ &cf_free,
+          /*preferredSize*/ NULL };
+    CFAllocatorRef cf_asan =
+        CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
+    CFAllocatorSetDefault(cf_asan);
+  }
+}
+}  // namespace __asan

Added: compiler-rt/trunk/lib/asan/asan_mapping.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_mapping.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_mapping.h (added)
+++ compiler-rt/trunk/lib/asan/asan_mapping.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,96 @@
+//===-- asan_mapping.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Defines ASan memory mapping.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_MAPPING_H
+#define ASAN_MAPPING_H
+
+#include "asan_internal.h"
+
+// The full explanation of the memory mapping could be found here:
+// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm
+
+#if ASAN_FLEXIBLE_MAPPING_AND_OFFSET == 1
+extern __attribute__((visibility("default"))) uintptr_t __asan_mapping_scale;
+extern __attribute__((visibility("default"))) uintptr_t __asan_mapping_offset;
+#define SHADOW_SCALE (__asan_mapping_scale)
+#define SHADOW_OFFSET (__asan_mapping_offset)
+#else
+#define SHADOW_SCALE (3)
+#if __WORDSIZE == 32
+#define SHADOW_OFFSET (1 << 29)
+#else
+#define SHADOW_OFFSET (1ULL << 44)
+#endif
+#endif  // ASAN_FLEXIBLE_MAPPING_AND_OFFSET
+
+#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
+#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) | (SHADOW_OFFSET))
+
+#if __WORDSIZE == 64
+  static const size_t kHighMemEnd = 0x00007fffffffffffUL;
+#else  // __WORDSIZE == 32
+  static const size_t kHighMemEnd = 0xffffffff;
+#endif  // __WORDSIZE
+
+
+#define kLowMemBeg      0
+#define kLowMemEnd      (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
+
+#define kLowShadowBeg   SHADOW_OFFSET
+#define kLowShadowEnd   MEM_TO_SHADOW(kLowMemEnd)
+
+#define kHighMemBeg     (MEM_TO_SHADOW(kHighMemEnd) + 1)
+
+#define kHighShadowBeg  MEM_TO_SHADOW(kHighMemBeg)
+#define kHighShadowEnd  MEM_TO_SHADOW(kHighMemEnd)
+
+#define kShadowGapBeg   (kLowShadowEnd ? kLowShadowEnd + 1 : 16 * kPageSize)
+#define kShadowGapEnd   (kHighShadowBeg - 1)
+
+#define kGlobalAndStackRedzone \
+      (SHADOW_GRANULARITY < 32 ? 32 : SHADOW_GRANULARITY)
+
+namespace __asan {
+
+static inline bool AddrIsInLowMem(uintptr_t a) {
+  return a < kLowMemEnd;
+}
+
+static inline bool AddrIsInLowShadow(uintptr_t a) {
+  return a >= kLowShadowBeg && a <= kLowShadowEnd;
+}
+
+static inline bool AddrIsInHighMem(uintptr_t a) {
+  return a >= kHighMemBeg && a <= kHighMemEnd;
+}
+
+static inline bool AddrIsInMem(uintptr_t a) {
+  return AddrIsInLowMem(a) || AddrIsInHighMem(a);
+}
+
+static inline uintptr_t MemToShadow(uintptr_t p) {
+  CHECK(AddrIsInMem(p));
+  return MEM_TO_SHADOW(p);
+}
+
+static inline bool AddrIsInHighShadow(uintptr_t a) {
+  return a >= kHighShadowBeg && a <=  kHighMemEnd;
+}
+
+static inline bool AddrIsInShadow(uintptr_t a) {
+  return AddrIsInLowShadow(a) || AddrIsInHighShadow(a);
+}
+
+}  // namespace __asan
+
+#endif  // ASAN_MAPPING_H

Added: compiler-rt/trunk/lib/asan/asan_poisoning.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_poisoning.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_poisoning.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_poisoning.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,134 @@
+//===-- asan_poisoning.cc ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Memory poisoning that can be made by user application.
+//===----------------------------------------------------------------------===//
+
+#include "asan_interceptors.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+
+#include <algorithm>
+
+namespace __asan {
+
+struct ShadowSegmentEndpoint {
+  uint8_t *chunk;
+  int8_t offset;  // in [0, SHADOW_GRANULARITY)
+  int8_t value;  // = *chunk;
+
+  explicit ShadowSegmentEndpoint(uintptr_t address) {
+    chunk = (uint8_t*)MemToShadow(address);
+    offset = address & (SHADOW_GRANULARITY - 1);
+    value = *chunk;
+  }
+};
+
+}  // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan;  // NOLINT
+
+// Current implementation of __asan_(un)poison_memory_region doesn't check
+// that user program (un)poisons the memory it owns. It poisons memory
+// conservatively, and unpoisons progressively to make sure asan shadow
+// mapping invariant is preserved (see detailed mapping description here:
+// http://code.google.com/p/address-sanitizer/wiki/AddressSanitizerAlgorithm).
+//
+// * if user asks to poison region [left, right), the program poisons
+// at least [left, AlignDown(right)).
+// * if user asks to unpoison region [left, right), the program unpoisons
+// at most [AlignDown(left), right).
+void __asan_poison_memory_region(void const volatile *addr, size_t size) {
+  if (!FLAG_allow_user_poisoning || size == 0) return;
+  uintptr_t beg_addr = (uintptr_t)addr;
+  uintptr_t end_addr = beg_addr + size;
+  if (FLAG_v >= 1) {
+    Printf("Trying to poison memory region [%p, %p)\n", beg_addr, end_addr);
+  }
+  ShadowSegmentEndpoint beg(beg_addr);
+  ShadowSegmentEndpoint end(end_addr);
+  if (beg.chunk == end.chunk) {
+    CHECK(beg.offset < end.offset);
+    int8_t value = beg.value;
+    CHECK(value == end.value);
+    // We can only poison memory if the byte in end.offset is unaddressable.
+    // No need to re-poison memory if it is poisoned already.
+    if (value > 0 && value <= end.offset) {
+      if (beg.offset > 0) {
+        *beg.chunk = std::min(value, beg.offset);
+      } else {
+        *beg.chunk = kAsanUserPoisonedMemoryMagic;
+      }
+    }
+    return;
+  }
+  CHECK(beg.chunk < end.chunk);
+  if (beg.offset > 0) {
+    // Mark bytes from beg.offset as unaddressable.
+    if (beg.value == 0) {
+      *beg.chunk = beg.offset;
+    } else {
+      *beg.chunk = std::min(beg.value, beg.offset);
+    }
+    beg.chunk++;
+  }
+  real_memset(beg.chunk, kAsanUserPoisonedMemoryMagic, end.chunk - beg.chunk);
+  // Poison if byte in end.offset is unaddressable.
+  if (end.value > 0 && end.value <= end.offset) {
+    *end.chunk = kAsanUserPoisonedMemoryMagic;
+  }
+}
+
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size) {
+  if (!FLAG_allow_user_poisoning || size == 0) return;
+  uintptr_t beg_addr = (uintptr_t)addr;
+  uintptr_t end_addr = beg_addr + size;
+  if (FLAG_v >= 1) {
+    Printf("Trying to unpoison memory region [%p, %p)\n", beg_addr, end_addr);
+  }
+  ShadowSegmentEndpoint beg(beg_addr);
+  ShadowSegmentEndpoint end(end_addr);
+  if (beg.chunk == end.chunk) {
+    CHECK(beg.offset < end.offset);
+    int8_t value = beg.value;
+    CHECK(value == end.value);
+    // We unpoison memory bytes up to enbytes up to end.offset if it is not
+    // unpoisoned already.
+    if (value != 0) {
+      *beg.chunk = std::max(value, end.offset);
+    }
+    return;
+  }
+  CHECK(beg.chunk < end.chunk);
+  if (beg.offset > 0) {
+    *beg.chunk = 0;
+    beg.chunk++;
+  }
+  real_memset(beg.chunk, 0, end.chunk - beg.chunk);
+  if (end.offset > 0 && end.value != 0) {
+    *end.chunk = std::max(end.value, end.offset);
+  }
+}
+
+bool __asan_address_is_poisoned(void const volatile *addr) {
+  const size_t kAccessSize = 1;
+  uintptr_t address = (uintptr_t)addr;
+  uint8_t *shadow_address = (uint8_t*)MemToShadow(address);
+  int8_t shadow_value = *shadow_address;
+  if (shadow_value) {
+    uint8_t last_accessed_byte = (address & (SHADOW_GRANULARITY - 1))
+                                 + kAccessSize - 1;
+    return (last_accessed_byte >= shadow_value);
+  }
+  return false;
+}

Added: compiler-rt/trunk/lib/asan/asan_printf.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_printf.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_printf.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_printf.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,181 @@
+//===-- asan_printf.cc ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Internal printf function, used inside ASan run-time library.
+// We can't use libc printf because we intercept some of the functions used
+// inside it.
+//===----------------------------------------------------------------------===//
+
+#include "asan_internal.h"
+#include "asan_interceptors.h"
+
+#include <stdarg.h>
+
+namespace __asan {
+
+void RawWrite(const char *buffer) {
+  static const char *kRawWriteError = "RawWrite can't output requested buffer!";
+  ssize_t length = (ssize_t)internal_strlen(buffer);
+  if (length != asan_write(2, buffer, length)) {
+    asan_write(2, kRawWriteError, internal_strlen(kRawWriteError));
+    ASAN_DIE;
+  }
+}
+
+static inline int AppendChar(char **buff, const char *buff_end, char c) {
+  if (*buff < buff_end) {
+    **buff = c;
+    (*buff)++;
+  }
+  return 1;
+}
+
+// Appends number in a given base to buffer. If its length is less than
+// "minimal_num_length", it is padded with leading zeroes.
+static int AppendUnsigned(char **buff, const char *buff_end, uint64_t num,
+                          uint8_t base, uint8_t minimal_num_length) {
+  size_t const kMaxLen = 30;
+  RAW_CHECK(base == 10 || base == 16);
+  RAW_CHECK(minimal_num_length < kMaxLen);
+  size_t num_buffer[kMaxLen];
+  size_t pos = 0;
+  do {
+    RAW_CHECK_MSG(pos < kMaxLen, "appendNumber buffer overflow");
+    num_buffer[pos++] = num % base;
+    num /= base;
+  } while (num > 0);
+  while (pos < minimal_num_length) num_buffer[pos++] = 0;
+  int result = 0;
+  while (pos-- > 0) {
+    size_t digit = num_buffer[pos];
+    result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
+                                                      : 'a' + digit - 10);
+  }
+  return result;
+}
+
+static inline int AppendSignedDecimal(char **buff, const char *buff_end,
+                                      int64_t num) {
+  int result = 0;
+  if (num < 0) {
+    result += AppendChar(buff, buff_end, '-');
+    num = -num;
+  }
+  result += AppendUnsigned(buff, buff_end, (uint64_t)num, 10, 0);
+  return result;
+}
+
+static inline int AppendString(char **buff, const char *buff_end,
+                               const char *s) {
+  // Avoid library functions like stpcpy here.
+  RAW_CHECK(s);
+  int result = 0;
+  for (; *s; s++) {
+    result += AppendChar(buff, buff_end, *s);
+  }
+  return result;
+}
+
+static inline int AppendPointer(char **buff, const char *buff_end,
+                                uint64_t ptr_value) {
+  int result = 0;
+  result += AppendString(buff, buff_end, "0x");
+  result += AppendUnsigned(buff, buff_end, ptr_value, 16,
+                           (__WORDSIZE == 64) ? 12 : 8);
+  return result;
+}
+
+static int VSNPrintf(char *buff, int buff_length,
+                     const char *format, va_list args) {
+  static const char *kPrintfFormatsHelp = "Supported Printf formats: "
+                                          "%%[l]{d,u,x}; %%p; %%s";
+  RAW_CHECK(format);
+  RAW_CHECK(buff_length > 0);
+  const char *buff_end = &buff[buff_length - 1];
+  const char *cur = format;
+  int result = 0;
+  for (; *cur; cur++) {
+    if (*cur == '%') {
+      cur++;
+      bool have_l = (*cur == 'l');
+      cur += have_l;
+      int64_t dval;
+      uint64_t uval, xval;
+      switch (*cur) {
+        case 'd': dval = have_l ? va_arg(args, intptr_t)
+                                : va_arg(args, int);
+                  result += AppendSignedDecimal(&buff, buff_end, dval);
+                  break;
+        case 'u': uval = have_l ? va_arg(args, uintptr_t)
+                                : va_arg(args, unsigned int);
+                  result += AppendUnsigned(&buff, buff_end, uval, 10, 0);
+                  break;
+        case 'x': xval = have_l ? va_arg(args, uintptr_t)
+                                : va_arg(args, unsigned int);
+                  result += AppendUnsigned(&buff, buff_end, xval, 16, 0);
+                  break;
+        case 'p': RAW_CHECK_MSG(!have_l, kPrintfFormatsHelp);
+                  result += AppendPointer(&buff, buff_end,
+                                          va_arg(args, uintptr_t));
+                  break;
+        case 's': RAW_CHECK_MSG(!have_l, kPrintfFormatsHelp);
+                  result += AppendString(&buff, buff_end, va_arg(args, char*));
+                  break;
+        default:  RAW_CHECK_MSG(false, kPrintfFormatsHelp);
+      }
+    } else {
+      result += AppendChar(&buff, buff_end, *cur);
+    }
+  }
+  RAW_CHECK(buff <= buff_end);
+  AppendChar(&buff, buff_end + 1, '\0');
+  return result;
+}
+
+void Printf(const char *format, ...) {
+  const int kLen = 1024 * 4;
+  char buffer[kLen];
+  va_list args;
+  va_start(args, format);
+  int needed_length = VSNPrintf(buffer, kLen, format, args);
+  va_end(args);
+  RAW_CHECK_MSG(needed_length < kLen, "Buffer in Printf is too short!\n");
+  RawWrite(buffer);
+}
+
+// Writes at most "length" symbols to "buffer" (including trailing '\0').
+// Returns the number of symbols that should have been written to buffer
+// (not including trailing '\0'). Thus, the string is truncated
+// iff return value is not less than "length".
+int SNPrintf(char *buffer, size_t length, const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  int needed_length = VSNPrintf(buffer, length, format, args);
+  va_end(args);
+  return needed_length;
+}
+
+// Like Printf, but prints the current PID before the output string.
+void Report(const char *format, ...) {
+  const int kLen = 1024 * 4;
+  char buffer[kLen];
+  int needed_length = SNPrintf(buffer, kLen, "==%d== ", getpid());
+  RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+  va_list args;
+  va_start(args, format);
+  needed_length += VSNPrintf(buffer + needed_length, kLen - needed_length,
+                             format, args);
+  va_end(args);
+  RAW_CHECK_MSG(needed_length < kLen, "Buffer in Report is too short!\n");
+  RawWrite(buffer);
+}
+
+}  // namespace __asan

Added: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,760 @@
+//===-- asan_rtl.cc ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Main file of the ASan run-time library.
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_lock.h"
+#ifdef __APPLE__
+#include "asan_mac.h"
+#endif
+#include "asan_mapping.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+#include "asan_thread_registry.h"
+
+#include <algorithm>
+#include <map>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+// must not include <setjmp.h> on Linux
+
+#ifndef ASAN_NEEDS_SEGV
+# define ASAN_NEEDS_SEGV 1
+#endif
+
+namespace __asan {
+
+// -------------------------- Flags ------------------------- {{{1
+static const size_t kMallocContextSize = 30;
+static int    FLAG_atexit;
+bool   FLAG_fast_unwind = true;
+
+size_t FLAG_redzone;  // power of two, >= 32
+bool   FLAG_mt;  // set to 0 if you have only one thread.
+size_t FLAG_quarantine_size;
+int    FLAG_demangle;
+bool   FLAG_symbolize;
+int    FLAG_v;
+int    FLAG_debug;
+bool   FLAG_poison_shadow;
+int    FLAG_report_globals;
+size_t FLAG_malloc_context_size = kMallocContextSize;
+uintptr_t FLAG_large_malloc;
+bool   FLAG_lazy_shadow;
+bool   FLAG_handle_segv;
+bool   FLAG_handle_sigill;
+bool   FLAG_replace_str;
+bool   FLAG_replace_intrin;
+bool   FLAG_replace_cfallocator;  // Used on Mac only.
+bool   FLAG_stats;
+size_t FLAG_max_malloc_fill_size = 0;
+bool   FLAG_use_fake_stack;
+int    FLAG_exitcode = EXIT_FAILURE;
+bool   FLAG_allow_user_poisoning;
+
+// -------------------------- Globals --------------------- {{{1
+int asan_inited;
+bool asan_init_is_running;
+
+// -------------------------- Interceptors ---------------- {{{1
+typedef int (*sigaction_f)(int signum, const struct sigaction *act,
+                           struct sigaction *oldact);
+typedef sig_t (*signal_f)(int signum, sig_t handler);
+typedef void (*longjmp_f)(void *env, int val);
+typedef longjmp_f _longjmp_f;
+typedef longjmp_f siglongjmp_f;
+typedef void (*__cxa_throw_f)(void *, void *, void *);
+typedef int (*pthread_create_f)(pthread_t *thread, const pthread_attr_t *attr,
+                                void *(*start_routine) (void *), void *arg);
+#ifdef __APPLE__
+dispatch_async_f_f real_dispatch_async_f;
+dispatch_sync_f_f real_dispatch_sync_f;
+dispatch_after_f_f real_dispatch_after_f;
+dispatch_barrier_async_f_f real_dispatch_barrier_async_f;
+dispatch_group_async_f_f real_dispatch_group_async_f;
+pthread_workqueue_additem_np_f real_pthread_workqueue_additem_np;
+#endif
+
+sigaction_f             real_sigaction;
+signal_f                real_signal;
+longjmp_f               real_longjmp;
+_longjmp_f              real__longjmp;
+siglongjmp_f            real_siglongjmp;
+__cxa_throw_f           real___cxa_throw;
+pthread_create_f        real_pthread_create;
+
+// -------------------------- Misc ---------------- {{{1
+void ShowStatsAndAbort() {
+  __asan_print_accumulated_stats();
+  ASAN_DIE;
+}
+
+static void PrintBytes(const char *before, uintptr_t *a) {
+  uint8_t *bytes = (uint8_t*)a;
+  size_t byte_num = (__WORDSIZE) / 8;
+  Printf("%s%p:", before, (uintptr_t)a);
+  for (size_t i = 0; i < byte_num; i++) {
+    Printf(" %lx%lx", bytes[i] >> 4, bytes[i] & 15);
+  }
+  Printf("\n");
+}
+
+// ---------------------- Thread ------------------------- {{{1
+static void *asan_thread_start(void *arg) {
+  AsanThread *t= (AsanThread*)arg;
+  asanThreadRegistry().SetCurrent(t);
+  return t->ThreadStart();
+}
+
+// ---------------------- mmap -------------------- {{{1
+static void OutOfMemoryMessage(const char *mem_type, size_t size) {
+  Report("ERROR: AddressSanitizer failed to allocate "
+         "0x%lx (%ld) bytes of %s\n",
+         size, size, mem_type);
+}
+
+static char *mmap_pages(size_t start_page, size_t n_pages, const char *mem_type,
+                        bool abort_on_failure = true) {
+  void *res = asan_mmap((void*)start_page, kPageSize * n_pages,
+                   PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
+  // Printf("%p => %p\n", (void*)start_page, res);
+  char *ch = (char*)res;
+  if (res == (void*)-1L && abort_on_failure) {
+    OutOfMemoryMessage(mem_type, n_pages * kPageSize);
+    ShowStatsAndAbort();
+  }
+  CHECK(res == (void*)start_page || res == (void*)-1L);
+  return ch;
+}
+
+// mmap range [beg, end]
+static char *mmap_range(uintptr_t beg, uintptr_t end, const char *mem_type) {
+  CHECK((beg % kPageSize) == 0);
+  CHECK(((end + 1) % kPageSize) == 0);
+  // Printf("mmap_range %p %p %ld\n", beg, end, (end - beg) / kPageSize);
+  return mmap_pages(beg, (end - beg + 1) / kPageSize, mem_type);
+}
+
+// protect range [beg, end]
+static void protect_range(uintptr_t beg, uintptr_t end) {
+  CHECK((beg % kPageSize) == 0);
+  CHECK(((end+1) % kPageSize) == 0);
+  // Printf("protect_range %p %p %ld\n", beg, end, (end - beg) / kPageSize);
+  void *res = asan_mmap((void*)beg, end - beg + 1,
+                   PROT_NONE,
+                   MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE, 0, 0);
+  CHECK(res == (void*)beg);
+}
+
+// ---------------------- DescribeAddress -------------------- {{{1
+static bool DescribeStackAddress(uintptr_t addr, uintptr_t access_size) {
+  AsanThread *t = asanThreadRegistry().FindThreadByStackAddress(addr);
+  if (!t) return false;
+  const intptr_t kBufSize = 4095;
+  char buf[kBufSize];
+  uintptr_t offset = 0;
+  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset);
+  // This string is created by the compiler and has the following form:
+  // "FunctioName n alloc_1 alloc_2 ... alloc_n"
+  // where alloc_i looks like "offset size len ObjectName ".
+  CHECK(frame_descr);
+  // Report the function name and the offset.
+  const char *name_end = real_strchr(frame_descr, ' ');
+  CHECK(name_end);
+  buf[0] = 0;
+  strncat(buf, frame_descr,
+          std::min(kBufSize, static_cast<intptr_t>(name_end - frame_descr)));
+  Printf("Address %p is located at offset %ld "
+         "in frame <%s> of T%d's stack:\n",
+         addr, offset, buf, t->tid());
+  // Report the number of stack objects.
+  char *p;
+  size_t n_objects = strtol(name_end, &p, 10);
+  CHECK(n_objects > 0);
+  Printf("  This frame has %ld object(s):\n", n_objects);
+  // Report all objects in this frame.
+  for (size_t i = 0; i < n_objects; i++) {
+    size_t beg, size;
+    intptr_t len;
+    beg  = strtol(p, &p, 10);
+    size = strtol(p, &p, 10);
+    len  = strtol(p, &p, 10);
+    if (beg <= 0 || size <= 0 || len < 0 || *p != ' ') {
+      Printf("AddressSanitizer can't parse the stack frame descriptor: |%s|\n",
+             frame_descr);
+      break;
+    }
+    p++;
+    buf[0] = 0;
+    strncat(buf, p, std::min(kBufSize, len));
+    p += len;
+    Printf("    [%ld, %ld) '%s'\n", beg, beg + size, buf);
+  }
+  Printf("HINT: this may be a false positive if your program uses "
+         "some custom stack unwind mechanism\n"
+         "      (longjmp and C++ exceptions *are* supported)\n");
+  t->summary()->Announce();
+  return true;
+}
+
+__attribute__((noinline))
+static void DescribeAddress(uintptr_t addr, uintptr_t access_size) {
+  // Check if this is a global.
+  if (DescribeAddrIfGlobal(addr))
+    return;
+
+  if (DescribeStackAddress(addr, access_size))
+    return;
+
+  // finally, check if this is a heap.
+  DescribeHeapAddress(addr, access_size);
+}
+
+// -------------------------- Run-time entry ------------------- {{{1
+void GetPcSpBpAx(void *context,
+                 uintptr_t *pc, uintptr_t *sp, uintptr_t *bp, uintptr_t *ax) {
+  ucontext_t *ucontext = (ucontext_t*)context;
+#ifdef __APPLE__
+# if __WORDSIZE == 64
+  *pc = ucontext->uc_mcontext->__ss.__rip;
+  *bp = ucontext->uc_mcontext->__ss.__rbp;
+  *sp = ucontext->uc_mcontext->__ss.__rsp;
+  *ax = ucontext->uc_mcontext->__ss.__rax;
+# else
+  *pc = ucontext->uc_mcontext->__ss.__eip;
+  *bp = ucontext->uc_mcontext->__ss.__ebp;
+  *sp = ucontext->uc_mcontext->__ss.__esp;
+  *ax = ucontext->uc_mcontext->__ss.__eax;
+# endif  // __WORDSIZE
+#else  // assume linux
+# if defined(__arm__)
+  *pc = ucontext->uc_mcontext.arm_pc;
+  *bp = ucontext->uc_mcontext.arm_fp;
+  *sp = ucontext->uc_mcontext.arm_sp;
+  *ax = ucontext->uc_mcontext.arm_r0;
+# elif __WORDSIZE == 64
+  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
+  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
+  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
+  *ax = ucontext->uc_mcontext.gregs[REG_RAX];
+# else
+  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
+  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
+  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
+  *ax = ucontext->uc_mcontext.gregs[REG_EAX];
+# endif  // __WORDSIZE
+#endif
+}
+
+static void     ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
+  uintptr_t addr = (uintptr_t)siginfo->si_addr;
+  if (AddrIsInShadow(addr) && FLAG_lazy_shadow) {
+    // We traped on access to a shadow address. Just map a large chunk around
+    // this address.
+    const uintptr_t chunk_size = kPageSize << 10;  // 4M
+    uintptr_t chunk = addr & ~(chunk_size - 1);
+    asan_mmap((void*)chunk, chunk_size,
+                   PROT_READ | PROT_WRITE,
+                   MAP_PRIVATE | MAP_ANON | MAP_FIXED, 0, 0);
+    return;
+  }
+  // Write the first message using the bullet-proof write.
+  if (13 != asan_write(2, "ASAN:SIGSEGV\n", 13)) ASAN_DIE;
+  uintptr_t pc, sp, bp, ax;
+  GetPcSpBpAx(context, &pc, &sp, &bp, &ax);
+  Report("ERROR: AddressSanitizer crashed on unknown address %p"
+         " (pc %p sp %p bp %p ax %p T%d)\n",
+         addr, pc, sp, bp, ax,
+         asanThreadRegistry().GetCurrentTidOrMinusOne());
+  Printf("AddressSanitizer can not provide additional info. ABORTING\n");
+  GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, false, pc, bp);
+  stack.PrintStack();
+  ShowStatsAndAbort();
+}
+
+static void     ASAN_OnSIGILL(int, siginfo_t *siginfo, void *context) {
+  // Write the first message using the bullet-proof write.
+  if (12 != asan_write(2, "ASAN:SIGILL\n", 12)) ASAN_DIE;
+  uintptr_t pc, sp, bp, ax;
+  GetPcSpBpAx(context, &pc, &sp, &bp, &ax);
+
+  uintptr_t addr = ax;
+
+  uint8_t *insn = (uint8_t*)pc;
+  CHECK(insn[0] == 0x0f && insn[1] == 0x0b);  // ud2
+  unsigned access_size_and_type = insn[2] - 0x50;
+  CHECK(access_size_and_type < 16);
+  bool is_write = access_size_and_type & 8;
+  int access_size = 1 << (access_size_and_type & 7);
+  __asan_report_error(pc, bp, sp, addr, is_write, access_size);
+}
+
+// exported functions
+#define ASAN_REPORT_ERROR(type, is_write, size) \
+extern "C" void __asan_report_ ## type ## size(uintptr_t addr)   \
+  __attribute__((visibility("default")));                        \
+extern "C" void __asan_report_ ## type ## size(uintptr_t addr) { \
+  GET_BP_PC_SP;                                                  \
+  __asan_report_error(pc, bp, sp, addr, is_write, size);  \
+}
+
+ASAN_REPORT_ERROR(load, false, 1)
+ASAN_REPORT_ERROR(load, false, 2)
+ASAN_REPORT_ERROR(load, false, 4)
+ASAN_REPORT_ERROR(load, false, 8)
+ASAN_REPORT_ERROR(load, false, 16)
+ASAN_REPORT_ERROR(store, true, 1)
+ASAN_REPORT_ERROR(store, true, 2)
+ASAN_REPORT_ERROR(store, true, 4)
+ASAN_REPORT_ERROR(store, true, 8)
+ASAN_REPORT_ERROR(store, true, 16)
+
+// Force the linker to keep the symbols for various ASan interface functions.
+// We want to keep those in the executable in order to let the instrumented
+// dynamic libraries access the symbol even if it is not used by the executable
+// itself. This should help if the build system is removing dead code at link
+// time.
+extern "C"
+void __asan_force_interface_symbols() {
+  volatile int fake_condition = 0;  // prevent dead condition elimination.
+  if (fake_condition) {
+    __asan_report_load1(NULL);
+    __asan_report_load2(NULL);
+    __asan_report_load4(NULL);
+    __asan_report_load8(NULL);
+    __asan_report_load16(NULL);
+    __asan_report_store1(NULL);
+    __asan_report_store2(NULL);
+    __asan_report_store4(NULL);
+    __asan_report_store8(NULL);
+    __asan_report_store16(NULL);
+    __asan_register_global(0, 0, NULL);
+    __asan_register_globals(NULL, 0);
+  }
+}
+
+// -------------------------- Init ------------------- {{{1
+static int64_t IntFlagValue(const char *flags, const char *flag,
+                            int64_t default_val) {
+  if (!flags) return default_val;
+  const char *str = strstr(flags, flag);
+  if (!str) return default_val;
+  return atoll(str + internal_strlen(flag));
+}
+
+static void asan_atexit() {
+  Printf("AddressSanitizer exit stats:\n");
+  __asan_print_accumulated_stats();
+}
+
+void CheckFailed(const char *cond, const char *file, int line) {
+  Report("CHECK failed: %s at %s:%d, pthread_self=%p\n",
+         cond, file, line, pthread_self());
+  PRINT_CURRENT_STACK();
+  ShowStatsAndAbort();
+}
+
+}  // namespace __asan
+
+// -------------------------- Interceptors ------------------- {{{1
+using namespace __asan;  // NOLINT
+
+#define OPERATOR_NEW_BODY \
+  GET_STACK_TRACE_HERE_FOR_MALLOC;\
+  return asan_memalign(0, size, &stack);
+
+void *operator new(size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
+void *operator new[](size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
+void *operator new(size_t size, std::nothrow_t const&) throw()
+{ OPERATOR_NEW_BODY; }
+void *operator new[](size_t size, std::nothrow_t const&) throw()
+{ OPERATOR_NEW_BODY; }
+
+#define OPERATOR_DELETE_BODY \
+  GET_STACK_TRACE_HERE_FOR_FREE(ptr);\
+  asan_free(ptr, &stack);
+
+void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
+void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
+void operator delete(void *ptr, std::nothrow_t const&) throw()
+{ OPERATOR_DELETE_BODY; }
+void operator delete[](void *ptr, std::nothrow_t const&) throw()
+{ OPERATOR_DELETE_BODY;}
+
+extern "C"
+#ifndef __APPLE__
+__attribute__((visibility("default")))
+#endif
+int WRAP(pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
+                         void *(*start_routine) (void *), void *arg) {
+  GET_STACK_TRACE_HERE(kStackTraceMax, /*fast_unwind*/false);
+  AsanThread *t = (AsanThread*)asan_malloc(sizeof(AsanThread), &stack);
+  AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+  CHECK(curr_thread || asanThreadRegistry().IsCurrentThreadDying());
+  new(t) AsanThread(asanThreadRegistry().GetCurrentTidOrMinusOne(),
+                    start_routine, arg, &stack);
+  return real_pthread_create(thread, attr, asan_thread_start, t);
+}
+
+static bool MySignal(int signum) {
+  if (FLAG_handle_sigill && signum == SIGILL) return true;
+  if (FLAG_handle_segv && signum == SIGSEGV) return true;
+#ifdef __APPLE__
+  if (FLAG_handle_segv && signum == SIGBUS) return true;
+#endif
+  return false;
+}
+
+static void MaybeInstallSigaction(int signum,
+                                  void (*handler)(int, siginfo_t *, void *)) {
+  if (!MySignal(signum))
+    return;
+  struct sigaction sigact;
+  real_memset(&sigact, 0, sizeof(sigact));
+  sigact.sa_sigaction = handler;
+  sigact.sa_flags = SA_SIGINFO;
+  CHECK(0 == real_sigaction(signum, &sigact, 0));
+}
+
+extern "C"
+sig_t WRAP(signal)(int signum, sig_t handler) {
+  if (!MySignal(signum)) {
+    return real_signal(signum, handler);
+  }
+  return NULL;
+}
+
+extern "C"
+int WRAP(sigaction)(int signum, const struct sigaction *act,
+                    struct sigaction *oldact) {
+  if (!MySignal(signum)) {
+    return real_sigaction(signum, act, oldact);
+  }
+  return 0;
+}
+
+
+static void UnpoisonStackFromHereToTop() {
+  int local_stack;
+  AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
+  CHECK(curr_thread);
+  uintptr_t top = curr_thread->stack_top();
+  uintptr_t bottom = ((uintptr_t)&local_stack - kPageSize) & ~(kPageSize-1);
+  uintptr_t top_shadow = MemToShadow(top);
+  uintptr_t bot_shadow = MemToShadow(bottom);
+  real_memset((void*)bot_shadow, 0, top_shadow - bot_shadow);
+}
+
+extern "C" void WRAP(longjmp)(void *env, int val) {
+  UnpoisonStackFromHereToTop();
+  real_longjmp(env, val);
+}
+
+extern "C" void WRAP(_longjmp)(void *env, int val) {
+  UnpoisonStackFromHereToTop();
+  real__longjmp(env, val);
+}
+
+extern "C" void WRAP(siglongjmp)(void *env, int val) {
+  UnpoisonStackFromHereToTop();
+  real_siglongjmp(env, val);
+}
+
+extern "C" void __cxa_throw(void *a, void *b, void *c);
+
+#if ASAN_HAS_EXCEPTIONS
+extern "C" void WRAP(__cxa_throw)(void *a, void *b, void *c) {
+  UnpoisonStackFromHereToTop();
+  real___cxa_throw(a, b, c);
+}
+#endif
+
+extern "C" {
+// intercept mlock and friends.
+// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
+// All functions return 0 (success).
+static void MlockIsUnsupported() {
+  static bool printed = 0;
+  if (printed) return;
+  printed = true;
+  Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n");
+}
+int mlock(const void *addr, size_t len) {
+  MlockIsUnsupported();
+  return 0;
+}
+int munlock(const void *addr, size_t len) {
+  MlockIsUnsupported();
+  return 0;
+}
+int mlockall(int flags) {
+  MlockIsUnsupported();
+  return 0;
+}
+int munlockall(void) {
+  MlockIsUnsupported();
+  return 0;
+}
+}  // extern "C"
+
+// ---------------------- Interface ---------------- {{{1
+int __asan_set_error_exit_code(int exit_code) {
+  int old = FLAG_exitcode;
+  FLAG_exitcode = exit_code;
+  return old;
+}
+
+void __asan_report_error(uintptr_t pc, uintptr_t bp, uintptr_t sp,
+                         uintptr_t addr, bool is_write, size_t access_size) {
+  // Do not print more than one report, otherwise they will mix up.
+  static int num_calls = 0;
+  if (AtomicInc(&num_calls) > 1) return;
+
+  Printf("=================================================================\n");
+  const char *bug_descr = "unknown-crash";
+  if (AddrIsInMem(addr)) {
+    uint8_t *shadow_addr = (uint8_t*)MemToShadow(addr);
+    uint8_t shadow_byte = shadow_addr[0];
+    if (shadow_byte > 0 && shadow_byte < 128) {
+      // we are in the partial right redzone, look at the next shadow byte.
+      shadow_byte = shadow_addr[1];
+    }
+    switch (shadow_byte) {
+      case kAsanHeapLeftRedzoneMagic:
+      case kAsanHeapRightRedzoneMagic:
+        bug_descr = "heap-buffer-overflow";
+        break;
+      case kAsanHeapFreeMagic:
+        bug_descr = "heap-use-after-free";
+        break;
+      case kAsanStackLeftRedzoneMagic:
+        bug_descr = "stack-buffer-underflow";
+        break;
+      case kAsanStackMidRedzoneMagic:
+      case kAsanStackRightRedzoneMagic:
+      case kAsanStackPartialRedzoneMagic:
+        bug_descr = "stack-buffer-overflow";
+        break;
+      case kAsanStackAfterReturnMagic:
+        bug_descr = "stack-use-after-return";
+        break;
+      case kAsanUserPoisonedMemoryMagic:
+        bug_descr = "use-after-poison";
+        break;
+      case kAsanGlobalRedzoneMagic:
+        bug_descr = "global-buffer-overflow";
+        break;
+    }
+  }
+
+  Report("ERROR: AddressSanitizer %s on address "
+         "%p at pc 0x%lx bp 0x%lx sp 0x%lx\n",
+         bug_descr, addr, pc, bp, sp);
+
+  Printf("%s of size %d at %p thread T%d\n",
+         access_size ? (is_write ? "WRITE" : "READ") : "ACCESS",
+         access_size, addr, asanThreadRegistry().GetCurrentTidOrMinusOne());
+
+  if (FLAG_debug) {
+    PrintBytes("PC: ", (uintptr_t*)pc);
+  }
+
+  GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax,
+                                 false,  // FLAG_fast_unwind,
+                                 pc, bp);
+  stack.PrintStack();
+
+  CHECK(AddrIsInMem(addr));
+
+  DescribeAddress(addr, access_size);
+
+  uintptr_t shadow_addr = MemToShadow(addr);
+  Report("ABORTING\n");
+  __asan_print_accumulated_stats();
+  Printf("Shadow byte and word:\n");
+  Printf("  %p: %x\n", shadow_addr, *(unsigned char*)shadow_addr);
+  uintptr_t aligned_shadow = shadow_addr & ~(kWordSize - 1);
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow));
+  Printf("More shadow bytes:\n");
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow-4*kWordSize));
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow-3*kWordSize));
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow-2*kWordSize));
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow-1*kWordSize));
+  PrintBytes("=>", (uintptr_t*)(aligned_shadow+0*kWordSize));
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow+1*kWordSize));
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow+2*kWordSize));
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow+3*kWordSize));
+  PrintBytes("  ", (uintptr_t*)(aligned_shadow+4*kWordSize));
+  ASAN_DIE;
+}
+
+void __asan_init() {
+  if (asan_inited) return;
+  asan_init_is_running = true;
+
+  // Make sure we are not statically linked.
+  AsanDoesNotSupportStaticLinkage();
+
+  // flags
+  const char *options = getenv("ASAN_OPTIONS");
+  FLAG_malloc_context_size =
+      IntFlagValue(options, "malloc_context_size=", kMallocContextSize);
+  CHECK(FLAG_malloc_context_size <= kMallocContextSize);
+
+  FLAG_max_malloc_fill_size =
+      IntFlagValue(options, "max_malloc_fill_size=", 0);
+
+  FLAG_v = IntFlagValue(options, "verbosity=", 0);
+
+  FLAG_redzone = IntFlagValue(options, "redzone=", 128);
+  CHECK(FLAG_redzone >= 32);
+  CHECK((FLAG_redzone & (FLAG_redzone - 1)) == 0);
+
+  FLAG_atexit = IntFlagValue(options, "atexit=", 0);
+  FLAG_poison_shadow = IntFlagValue(options, "poison_shadow=", 1);
+  FLAG_report_globals = IntFlagValue(options, "report_globals=", 1);
+  FLAG_lazy_shadow = IntFlagValue(options, "lazy_shadow=", 0);
+  FLAG_handle_segv = IntFlagValue(options, "handle_segv=",
+                                         ASAN_NEEDS_SEGV);
+  FLAG_handle_sigill = IntFlagValue(options, "handle_sigill=", 0);
+  FLAG_stats = IntFlagValue(options, "stats=", 0);
+  FLAG_symbolize = IntFlagValue(options, "symbolize=", 1);
+  FLAG_demangle = IntFlagValue(options, "demangle=", 1);
+  FLAG_debug = IntFlagValue(options, "debug=", 0);
+  FLAG_replace_cfallocator = IntFlagValue(options, "replace_cfallocator=", 1);
+  FLAG_fast_unwind = IntFlagValue(options, "fast_unwind=", 1);
+  FLAG_mt = IntFlagValue(options, "mt=", 1);
+  FLAG_replace_str = IntFlagValue(options, "replace_str=", 1);
+  FLAG_replace_intrin = IntFlagValue(options, "replace_intrin=", 0);
+  FLAG_use_fake_stack = IntFlagValue(options, "use_fake_stack=", 1);
+  FLAG_exitcode = IntFlagValue(options, "exitcode=", EXIT_FAILURE);
+  FLAG_allow_user_poisoning = IntFlagValue(options,
+                                           "allow_user_poisoning=", 1);
+
+  if (FLAG_atexit) {
+    atexit(asan_atexit);
+  }
+
+  FLAG_quarantine_size =
+      IntFlagValue(options, "quarantine_size=", 1UL << 28);
+
+  // interceptors
+  InitializeAsanInterceptors();
+
+  ReplaceSystemMalloc();
+
+  INTERCEPT_FUNCTION(sigaction);
+  INTERCEPT_FUNCTION(signal);
+  INTERCEPT_FUNCTION(longjmp);
+  INTERCEPT_FUNCTION(_longjmp);
+  INTERCEPT_FUNCTION(__cxa_throw);
+  INTERCEPT_FUNCTION(pthread_create);
+#ifdef __APPLE__
+  INTERCEPT_FUNCTION(dispatch_async_f);
+  INTERCEPT_FUNCTION(dispatch_sync_f);
+  INTERCEPT_FUNCTION(dispatch_after_f);
+  INTERCEPT_FUNCTION(dispatch_barrier_async_f);
+  INTERCEPT_FUNCTION(dispatch_group_async_f);
+  // We don't need to intercept pthread_workqueue_additem_np() to support the
+  // libdispatch API, but it helps us to debug the unsupported functions. Let's
+  // intercept it only during verbose runs.
+  if (FLAG_v >= 2) {
+    INTERCEPT_FUNCTION(pthread_workqueue_additem_np);
+  }
+#else
+  // On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
+  // there.
+  INTERCEPT_FUNCTION(siglongjmp);
+#endif
+
+  MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
+  MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
+  MaybeInstallSigaction(SIGILL, ASAN_OnSIGILL);
+
+  if (FLAG_v) {
+    Printf("|| `[%p, %p]` || HighMem    ||\n", kHighMemBeg, kHighMemEnd);
+    Printf("|| `[%p, %p]` || HighShadow ||\n",
+           kHighShadowBeg, kHighShadowEnd);
+    Printf("|| `[%p, %p]` || ShadowGap  ||\n",
+           kShadowGapBeg, kShadowGapEnd);
+    Printf("|| `[%p, %p]` || LowShadow  ||\n",
+           kLowShadowBeg, kLowShadowEnd);
+    Printf("|| `[%p, %p]` || LowMem     ||\n", kLowMemBeg, kLowMemEnd);
+    Printf("MemToShadow(shadow): %p %p %p %p\n",
+           MEM_TO_SHADOW(kLowShadowBeg),
+           MEM_TO_SHADOW(kLowShadowEnd),
+           MEM_TO_SHADOW(kHighShadowBeg),
+           MEM_TO_SHADOW(kHighShadowEnd));
+    Printf("red_zone=%ld\n", FLAG_redzone);
+    Printf("malloc_context_size=%ld\n", (int)FLAG_malloc_context_size);
+    Printf("fast_unwind=%d\n", (int)FLAG_fast_unwind);
+
+    Printf("SHADOW_SCALE: %lx\n", SHADOW_SCALE);
+    Printf("SHADOW_GRANULARITY: %lx\n", SHADOW_GRANULARITY);
+    Printf("SHADOW_OFFSET: %lx\n", SHADOW_OFFSET);
+    CHECK(SHADOW_SCALE >= 3 && SHADOW_SCALE <= 7);
+  }
+
+  if (__WORDSIZE == 64) {
+    // Disable core dumper -- it makes little sense to dump 16T+ core.
+    struct rlimit nocore;
+    nocore.rlim_cur = 0;
+    nocore.rlim_max = 0;
+    setrlimit(RLIMIT_CORE, &nocore);
+  }
+
+  {
+    if (!FLAG_lazy_shadow) {
+      if (kLowShadowBeg != kLowShadowEnd) {
+        // mmap the low shadow plus one page.
+        mmap_range(kLowShadowBeg - kPageSize, kLowShadowEnd, "LowShadow");
+      }
+      // mmap the high shadow.
+      mmap_range(kHighShadowBeg, kHighShadowEnd, "HighShadow");
+    }
+    // protect the gap
+    protect_range(kShadowGapBeg, kShadowGapEnd);
+  }
+
+  // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
+  // should be set to 1 prior to initializing the threads.
+  asan_inited = 1;
+  asan_init_is_running = false;
+
+  asanThreadRegistry().Init();
+  asanThreadRegistry().GetMain()->ThreadStart();
+  __asan_force_interface_symbols();  // no-op.
+
+  if (FLAG_v) {
+    Report("AddressSanitizer r%s Init done ***\n", ASAN_REVISION);
+  }
+}

Added: compiler-rt/trunk/lib/asan/asan_stack.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_stack.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_stack.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_stack.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,280 @@
+//===-- asan_stack.cc -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Code for ASan stack trace.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+#include "asan_lock.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "asan_thread_registry.h"
+
+#include <string.h>
+
+#ifdef ASAN_USE_SYSINFO
+#include "sysinfo/sysinfo.h"
+#endif
+
+#ifdef ASAN_USE_EXTERNAL_SYMBOLIZER
+extern bool
+ASAN_USE_EXTERNAL_SYMBOLIZER(const void *pc, char *out, int out_size);
+#endif
+
+namespace __asan {
+
+// ----------------------- ProcSelfMaps ----------------------------- {{{1
+#ifdef ASAN_USE_SYSINFO
+class ProcSelfMaps {
+ public:
+  void Init() {
+    ScopedLock lock(&mu_);
+    if (map_size_ != 0) return;  // already inited
+    if (FLAG_v >= 2) {
+      Printf("ProcSelfMaps::Init()\n");
+    }
+    ProcMapsIterator it(0, &proc_self_maps_);   // 0 means "current pid"
+
+    uint64 start, end, offset;
+    int64 inode;
+    char *flags, *filename;
+    CHECK(map_size_ == 0);
+    while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) {
+      CHECK(map_size_ < kMaxProcSelfMapsSize);
+      Mapping &mapping = memory_map[map_size_];
+      mapping.beg = start;
+      mapping.end = end;
+      mapping.offset = offset;
+      real_strncpy(mapping.name,
+                   filename, ASAN_ARRAY_SIZE(mapping.name));
+      mapping.name[ASAN_ARRAY_SIZE(mapping.name) - 1] = 0;
+      if (FLAG_v >= 2) {
+        Printf("[%ld] [%p,%p] off %p %s\n", map_size_,
+               mapping.beg, mapping.end, mapping.offset, mapping.name);
+      }
+      map_size_++;
+    }
+  }
+
+  void Print() {
+    Printf("%s\n", proc_self_maps_);
+  }
+
+  void PrintPc(uintptr_t pc, int idx) {
+    for (size_t i = 0; i < map_size_; i++) {
+      Mapping &m = memory_map[i];
+      if (pc >= m.beg && pc < m.end) {
+        uintptr_t offset = pc - m.beg;
+        if (i == 0) offset = pc;
+        Printf("    #%d 0x%lx (%s+0x%lx)\n", idx, pc, m.name, offset);
+        return;
+      }
+    }
+    Printf("  #%d 0x%lx\n", idx, pc);
+  }
+
+ private:
+  void copy_until_new_line(const char *str, char *dest, size_t max_size) {
+    size_t i = 0;
+    for (; str[i] && str[i] != '\n' && i < max_size - 1; i++) {
+      dest[i] = str[i];
+    }
+    dest[i] = 0;
+  }
+
+
+  struct Mapping {
+    uintptr_t beg, end, offset;
+    char name[1000];
+  };
+  static const size_t kMaxNumMapEntries = 4096;
+  static const size_t kMaxProcSelfMapsSize = 1 << 20;
+  ProcMapsIterator::Buffer proc_self_maps_;
+  size_t map_size_;
+  Mapping memory_map[kMaxNumMapEntries];
+
+  static AsanLock mu_;
+};
+
+static ProcSelfMaps proc_self_maps;
+AsanLock ProcSelfMaps::mu_(LINKER_INITIALIZED);
+
+
+void AsanStackTrace::PrintStack(uintptr_t *addr, size_t size) {
+  proc_self_maps.Init();
+  for (size_t i = 0; i < size && addr[i]; i++) {
+    uintptr_t pc = addr[i];
+    // int line;
+    proc_self_maps.PrintPc(pc, i);
+    // Printf("  #%ld 0x%lx %s\n", i, pc, rtn.c_str());
+  }
+}
+#elif defined(ASAN_USE_EXTERNAL_SYMBOLIZER)
+void AsanStackTrace::PrintStack(uintptr_t *addr, size_t size) {
+  for (size_t i = 0; i < size && addr[i]; i++) {
+    uintptr_t pc = addr[i];
+    char buff[4096];
+    ASAN_USE_EXTERNAL_SYMBOLIZER((void*)pc, buff, sizeof(buff));
+    Printf("  #%ld 0x%lx %s\n", i, pc, buff);
+  }
+}
+
+#else  // ASAN_USE_SYSINFO
+void AsanStackTrace::PrintStack(uintptr_t *addr, size_t size) {
+  for (size_t i = 0; i < size && addr[i]; i++) {
+    uintptr_t pc = addr[i];
+    Printf("  #%ld 0x%lx\n", i, pc);
+  }
+}
+#endif  // ASAN_USE_SYSINFO
+
+#ifdef __arm__
+#define UNWIND_STOP _URC_END_OF_STACK
+#define UNWIND_CONTINUE _URC_OK
+#else
+#define UNWIND_STOP _URC_NORMAL_STOP
+#define UNWIND_CONTINUE _URC_NO_REASON
+#endif
+
+// ----------------------- AsanStackTrace ----------------------------- {{{1
+uintptr_t AsanStackTrace::GetCurrentPc() {
+  return GET_CALLER_PC();
+}
+
+void AsanStackTrace::FastUnwindStack(uintptr_t pc, uintptr_t bp) {
+  CHECK(size == 0 && trace[0] == pc);
+  size = 1;
+  if (!asan_inited) return;
+  AsanThread *t = asanThreadRegistry().GetCurrent();
+  if (!t) return;
+  uintptr_t *frame = (uintptr_t*)bp;
+  uintptr_t *prev_frame = frame;
+  uintptr_t *top = (uintptr_t*)t->stack_top();
+  uintptr_t *bottom = (uintptr_t*)t->stack_bottom();
+  while (frame >= prev_frame &&
+         frame < top &&
+         frame > bottom &&
+         size < max_size) {
+    uintptr_t pc1 = frame[1];
+    if (pc1 != pc) {
+      trace[size++] = pc1;
+    }
+    prev_frame = frame;
+    frame = (uintptr_t*)frame[0];
+  }
+}
+
+// On 32-bits we don't compress stack traces.
+// On 64-bits we compress stack traces: if a given pc differes slightly from
+// the previous one, we record a 31-bit offset instead of the full pc.
+size_t AsanStackTrace::CompressStack(AsanStackTrace *stack,
+                                   uint32_t *compressed, size_t size) {
+#if __WORDSIZE == 32
+  // Don't compress, just copy.
+  size_t res = 0;
+  for (size_t i = 0; i < stack->size && i < size; i++) {
+    compressed[i] = stack->trace[i];
+    res++;
+  }
+  for (size_t i = stack->size; i < size; i++) {
+    compressed[i] = 0;
+  }
+#else  // 64 bits, compress.
+  uintptr_t prev_pc = 0;
+  const uintptr_t kMaxOffset = (1ULL << 30) - 1;
+  uintptr_t c_index = 0;
+  size_t res = 0;
+  for (size_t i = 0, n = stack->size; i < n; i++) {
+    uintptr_t pc = stack->trace[i];
+    if (!pc) break;
+    if ((int64_t)pc < 0) break;
+    // Printf("C pc[%ld] %lx\n", i, pc);
+    if (prev_pc - pc < kMaxOffset || pc - prev_pc < kMaxOffset) {
+      uintptr_t offset = (int64_t)(pc - prev_pc);
+      offset |= (1U << 31);
+      if (c_index >= size) break;
+      // Printf("C co[%ld] offset %lx\n", i, offset);
+      compressed[c_index++] = offset;
+    } else {
+      uintptr_t hi = pc >> 32;
+      uintptr_t lo = (pc << 32) >> 32;
+      CHECK((hi & (1 << 31)) == 0);
+      if (c_index + 1 >= size) break;
+      // Printf("C co[%ld] hi/lo: %lx %lx\n", c_index, hi, lo);
+      compressed[c_index++] = hi;
+      compressed[c_index++] = lo;
+    }
+    res++;
+    prev_pc = pc;
+  }
+  for (size_t i = c_index; i < size; i++) {
+    compressed[i] = 0;
+  }
+#endif  // __WORDSIZE
+
+  // debug-only code
+#if 0
+  AsanStackTrace check_stack;
+  UncompressStack(&check_stack, compressed, size);
+  if (res < check_stack.size) {
+    Printf("res %ld check_stack.size %ld; c_size %ld\n", res,
+           check_stack.size, size);
+  }
+  // |res| may be greater than check_stack.size, because
+  // UncompressStack(CompressStack(stack)) eliminates the 0x0 frames.
+  CHECK(res >= check_stack.size);
+  CHECK(0 == memcmp(check_stack.trace, stack->trace,
+                    check_stack.size * sizeof(uintptr_t)));
+#endif
+
+  return res;
+}
+
+void AsanStackTrace::UncompressStack(AsanStackTrace *stack,
+                                     uint32_t *compressed, size_t size) {
+#if __WORDSIZE == 32
+  // Don't uncompress, just copy.
+  stack->size = 0;
+  for (size_t i = 0; i < size && i < kStackTraceMax; i++) {
+    if (!compressed[i]) break;
+    stack->size++;
+    stack->trace[i] = compressed[i];
+  }
+#else  // 64 bits, uncompress
+  uintptr_t prev_pc = 0;
+  stack->size = 0;
+  for (size_t i = 0; i < size && stack->size < kStackTraceMax; i++) {
+    uint32_t x = compressed[i];
+    uintptr_t pc = 0;
+    if (x & (1U << 31)) {
+      // Printf("U co[%ld] offset: %x\n", i, x);
+      // this is an offset
+      int32_t offset = x;
+      offset = (offset << 1) >> 1;  // remove the 31-byte and sign-extend.
+      pc = prev_pc + offset;
+      CHECK(pc);
+    } else {
+      // CHECK(i + 1 < size);
+      if (i + 1 >= size) break;
+      uintptr_t hi = x;
+      uintptr_t lo = compressed[i+1];
+      // Printf("U co[%ld] hi/lo: %lx %lx\n", i, hi, lo);
+      i++;
+      pc = (hi << 32) | lo;
+      if (!pc) break;
+    }
+    // Printf("U pc[%ld] %lx\n", stack->size, pc);
+    stack->trace[stack->size++] = pc;
+    prev_pc = pc;
+  }
+#endif  // __WORDSIZE
+}
+
+}  // namespace __asan

Added: compiler-rt/trunk/lib/asan/asan_stack.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_stack.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_stack.h (added)
+++ compiler-rt/trunk/lib/asan/asan_stack.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,94 @@
+//===-- asan_stack.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_stack.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_STACK_H
+#define ASAN_STACK_H
+
+#include "asan_internal.h"
+
+namespace __asan {
+
+static const size_t kStackTraceMax = 64;
+
+struct AsanStackTrace {
+  size_t size;
+  size_t max_size;
+  uintptr_t trace[kStackTraceMax];
+  static void PrintStack(uintptr_t *addr, size_t size);
+  void PrintStack() {
+    PrintStack(this->trace, this->size);
+  }
+  void CopyTo(uintptr_t *dst, size_t dst_size) {
+    for (size_t i = 0; i < size && i < dst_size; i++)
+      dst[i] = trace[i];
+    for (size_t i = size; i < dst_size; i++)
+      dst[i] = 0;
+  }
+
+  void CopyFrom(uintptr_t *src, size_t src_size) {
+    size = src_size;
+    if (size > kStackTraceMax) size = kStackTraceMax;
+    for (size_t i = 0; i < size; i++) {
+      trace[i] = src[i];
+    }
+  }
+
+  void FastUnwindStack(uintptr_t pc, uintptr_t bp);
+//  static _Unwind_Reason_Code Unwind_Trace(
+//      struct _Unwind_Context *ctx, void *param);
+  static uintptr_t GetCurrentPc();
+
+  static size_t CompressStack(AsanStackTrace *stack,
+                            uint32_t *compressed, size_t size);
+  static void UncompressStack(AsanStackTrace *stack,
+                              uint32_t *compressed, size_t size);
+  size_t full_frame_count;
+};
+
+}  // namespace __asan
+
+// Get the stack trace with the given pc and bp.
+// The pc will be in the position 0 of the resulting stack trace.
+// The bp may refer to the current frame or to the caller's frame.
+// fast_unwind is currently unused.
+#define GET_STACK_TRACE_WITH_PC_AND_BP(max_s, fast_unwind, pc, bp)  \
+  AsanStackTrace stack;                             \
+  {                                                 \
+    uintptr_t saved_pc = pc;                        \
+    uintptr_t saved_bp = bp;                        \
+    stack.size = 0;                                 \
+    stack.full_frame_count = 0;                     \
+    stack.trace[0] = saved_pc;                      \
+    if ((max_s) > 1) {                              \
+      stack.max_size = max_s;                       \
+      stack.FastUnwindStack(saved_pc, saved_bp);    \
+    }                                               \
+  }                                                 \
+
+#define GET_STACK_TRACE_HERE(max_size, fast_unwind)         \
+  GET_STACK_TRACE_WITH_PC_AND_BP(max_size, fast_unwind,     \
+     AsanStackTrace::GetCurrentPc(), GET_CURRENT_FRAME())   \
+
+#define GET_STACK_TRACE_HERE_FOR_MALLOC         \
+  GET_STACK_TRACE_HERE(FLAG_malloc_context_size, FLAG_fast_unwind)
+
+#define GET_STACK_TRACE_HERE_FOR_FREE(ptr) \
+  GET_STACK_TRACE_HERE(FLAG_malloc_context_size, FLAG_fast_unwind)
+
+#define PRINT_CURRENT_STACK()                    \
+  {                                              \
+    GET_STACK_TRACE_HERE(kStackTraceMax, false); \
+    stack.PrintStack();                          \
+  }                                              \
+
+#endif  // ASAN_STACK_H

Added: compiler-rt/trunk/lib/asan/asan_stats.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_stats.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_stats.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_stats.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,94 @@
+//===-- asan_stats.cc -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Code related to statistics collected by AddressSanitizer.
+//===----------------------------------------------------------------------===//
+#include "asan_interceptors.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_lock.h"
+#include "asan_stats.h"
+#include "asan_thread_registry.h"
+
+namespace __asan {
+
+AsanStats::AsanStats() {
+  CHECK(real_memset != NULL);
+  real_memset(this, 0, sizeof(AsanStats));
+}
+
+static void PrintMallocStatsArray(const char *prefix,
+                                  size_t (&array)[kNumberOfSizeClasses]) {
+  Printf("%s", prefix);
+  for (size_t i = 0; i < kNumberOfSizeClasses; i++) {
+    if (!array[i]) continue;
+    Printf("%ld:%ld; ", i, array[i]);
+  }
+  Printf("\n");
+}
+
+void AsanStats::Print() {
+  Printf("Stats: %ldM malloced (%ldM for red zones) by %ld calls\n",
+         malloced>>20, malloced_redzones>>20, mallocs);
+  Printf("Stats: %ldM realloced by %ld calls\n", realloced>>20, reallocs);
+  Printf("Stats: %ldM freed by %ld calls\n", freed>>20, frees);
+  Printf("Stats: %ldM really freed by %ld calls\n",
+         really_freed>>20, real_frees);
+  Printf("Stats: %ldM (%ld full pages) mmaped in %ld calls\n",
+         mmaped>>20, mmaped / kPageSize, mmaps);
+
+  PrintMallocStatsArray("  mmaps   by size class: ", mmaped_by_size);
+  PrintMallocStatsArray("  mallocs by size class: ", malloced_by_size);
+  PrintMallocStatsArray("  frees   by size class: ", freed_by_size);
+  PrintMallocStatsArray("  rfrees  by size class: ", really_freed_by_size);
+  Printf("Stats: malloc large: %ld small slow: %ld\n",
+         malloc_large, malloc_small_slow);
+}
+
+static void PrintAccumulatedStats() {
+  if (!FLAG_stats) return;
+  AsanStats stats = asanThreadRegistry().GetAccumulatedStats();
+  // Use lock to keep reports from mixing up.
+  static AsanLock print_lock(LINKER_INITIALIZED);
+  ScopedLock lock(&print_lock);
+  stats.Print();
+}
+
+}  // namespace __asan
+
+// ---------------------- Interface ---------------- {{{1
+using namespace __asan;  // NOLINT
+
+size_t __asan_get_current_allocated_bytes() {
+  return asanThreadRegistry().GetCurrentAllocatedBytes();
+}
+
+size_t __asan_get_heap_size() {
+  return asanThreadRegistry().GetHeapSize();
+}
+
+size_t __asan_get_free_bytes() {
+  return asanThreadRegistry().GetFreeBytes();
+}
+
+size_t __asan_get_unmapped_bytes() {
+  return 0;
+}
+
+bool __asan_enable_statistics(bool enable) {
+  bool old_flag = FLAG_stats;
+  FLAG_stats = enable;
+  return old_flag;
+}
+
+void __asan_print_accumulated_stats() {
+  PrintAccumulatedStats();
+}

Added: compiler-rt/trunk/lib/asan/asan_stats.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_stats.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_stats.h (added)
+++ compiler-rt/trunk/lib/asan/asan_stats.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,59 @@
+//===-- asan_stats.h --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for statistics.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_STATS_H
+#define ASAN_STATS_H
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+
+namespace __asan {
+
+// AsanStats struct is NOT thread-safe.
+// Each AsanThread has its own AsanStats, which are sometimes flushed
+// to the accumulated AsanStats.
+struct AsanStats {
+  // AsanStats must be a struct consisting of size_t fields only.
+  // When merging two AsanStats structs, we treat them as arrays of size_t.
+  size_t mallocs;
+  size_t malloced;
+  size_t malloced_redzones;
+  size_t frees;
+  size_t freed;
+  size_t real_frees;
+  size_t really_freed;
+  size_t really_freed_redzones;
+  size_t reallocs;
+  size_t realloced;
+  size_t mmaps;
+  size_t mmaped;
+  size_t mmaped_by_size[kNumberOfSizeClasses];
+  size_t malloced_by_size[kNumberOfSizeClasses];
+  size_t freed_by_size[kNumberOfSizeClasses];
+  size_t really_freed_by_size[kNumberOfSizeClasses];
+
+  size_t malloc_large;
+  size_t malloc_small_slow;
+
+  // Ctor for global AsanStats (accumulated stats and main thread stats).
+  explicit AsanStats(LinkerInitialized) { }
+  // Default ctor for thread-local stats.
+  AsanStats();
+
+  // Prints formatted stats to stderr.
+  void Print();
+};
+
+}  // namespace __asan
+
+#endif  // ASAN_STATS_H

Added: compiler-rt/trunk/lib/asan/asan_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_thread.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,139 @@
+//===-- asan_thread.cc ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Thread-related code.
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+#include "asan_interceptors.h"
+#include "asan_thread.h"
+#include "asan_thread_registry.h"
+#include "asan_mapping.h"
+
+#include <sys/mman.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+namespace __asan {
+
+AsanThread::AsanThread(LinkerInitialized x)
+    : fake_stack_(x),
+      malloc_storage_(x),
+      stats_(x) { }
+
+AsanThread::AsanThread(int parent_tid, void *(*start_routine) (void *),
+                       void *arg, AsanStackTrace *stack)
+    : start_routine_(start_routine),
+      arg_(arg) {
+  asanThreadRegistry().RegisterThread(this, parent_tid, stack);
+}
+
+AsanThread::~AsanThread() {
+  asanThreadRegistry().UnregisterThread(this);
+  fake_stack().Cleanup();
+  // We also clear the shadow on thread destruction because
+  // some code may still be executing in later TSD destructors
+  // and we don't want it to have any poisoned stack.
+  ClearShadowForThreadStack();
+}
+
+void AsanThread::ClearShadowForThreadStack() {
+  uintptr_t shadow_bot = MemToShadow(stack_bottom_);
+  uintptr_t shadow_top = MemToShadow(stack_top_);
+  real_memset((void*)shadow_bot, 0, shadow_top - shadow_bot);
+}
+
+void *AsanThread::ThreadStart() {
+  SetThreadStackTopAndBottom();
+  fake_stack_.Init(stack_size());
+  if (FLAG_v >= 1) {
+    int local = 0;
+    Report("T%d: stack [%p,%p) size 0x%lx; local=%p, pthread_self=%p\n",
+           tid(), stack_bottom_, stack_top_,
+           stack_top_ - stack_bottom_, &local, pthread_self());
+  }
+
+  CHECK(AddrIsInMem(stack_bottom_));
+  CHECK(AddrIsInMem(stack_top_));
+
+  ClearShadowForThreadStack();
+
+  if (!start_routine_) {
+    // start_routine_ == NULL if we're on the main thread or on one of the
+    // OS X libdispatch worker threads. But nobody is supposed to call
+    // ThreadStart() for the worker threads.
+    CHECK(tid() == 0);
+    return 0;
+  }
+
+  void *res = start_routine_(arg_);
+  malloc_storage().CommitBack();
+
+  if (FLAG_v >= 1) {
+    Report("T%d exited\n", tid());
+  }
+
+  return res;
+}
+
+const char *AsanThread::GetFrameNameByAddr(uintptr_t addr, uintptr_t *offset) {
+  uintptr_t bottom = 0;
+  bool is_fake_stack = false;
+  if (AddrIsInStack(addr)) {
+    bottom = stack_bottom();
+  } else {
+    bottom = fake_stack().AddrIsInFakeStack(addr);
+    CHECK(bottom);
+    is_fake_stack = true;
+  }
+  uintptr_t aligned_addr = addr & ~(__WORDSIZE/8 - 1);  // align addr.
+  uintptr_t *ptr = (uintptr_t*)aligned_addr;
+  while (ptr >= (uintptr_t*)bottom) {
+    if (ptr[0] == kCurrentStackFrameMagic ||
+        (is_fake_stack && ptr[0] == kRetiredStackFrameMagic)) {
+      *offset = addr - (uintptr_t)ptr;
+      return (const char*)ptr[1];
+    }
+    ptr--;
+  }
+  *offset = 0;
+  return "UNKNOWN";
+}
+
+void AsanThread::SetThreadStackTopAndBottom() {
+#ifdef __APPLE__
+  size_t stacksize = pthread_get_stacksize_np(pthread_self());
+  void *stackaddr = pthread_get_stackaddr_np(pthread_self());
+  stack_top_ = (uintptr_t)stackaddr;
+  stack_bottom_ = stack_top_ - stacksize;
+  int local;
+  CHECK(AddrIsInStack((uintptr_t)&local));
+#else
+  pthread_attr_t attr;
+  CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
+  size_t stacksize = 0;
+  void *stackaddr = NULL;
+  pthread_attr_getstack(&attr, &stackaddr, &stacksize);
+  pthread_attr_destroy(&attr);
+
+  stack_top_ = (uintptr_t)stackaddr + stacksize;
+  stack_bottom_ = (uintptr_t)stackaddr;
+  // When running with unlimited stack size, we still want to set some limit.
+  // The unlimited stack size is caused by 'ulimit -s unlimited'.
+  // Also, for some reason, GNU make spawns subrocesses with unlimited stack.
+  if (stacksize > kMaxThreadStackSize) {
+    stack_bottom_ = stack_top_ - kMaxThreadStackSize;
+  }
+  CHECK(AddrIsInStack((uintptr_t)&attr));
+#endif
+}
+
+}  // namespace __asan

Added: compiler-rt/trunk/lib/asan/asan_thread.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread.h (added)
+++ compiler-rt/trunk/lib/asan/asan_thread.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,107 @@
+//===-- asan_thread.h -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_thread.cc.
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_THREAD_H
+#define ASAN_THREAD_H
+
+#include "asan_allocator.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+
+namespace __asan {
+
+const size_t kMaxThreadStackSize = 16 * (1 << 20);  // 16M
+
+class AsanThread;
+
+// These objects are created for every thread and are never deleted,
+// so we can find them by tid even if the thread is long dead.
+class AsanThreadSummary {
+ public:
+  explicit AsanThreadSummary(LinkerInitialized) { }  // for T0.
+  AsanThreadSummary(int tid, int parent_tid, AsanStackTrace *stack)
+      : tid_(tid),
+        parent_tid_(parent_tid),
+        announced_(false) {
+    if (stack) {
+      stack_ = *stack;
+    }
+    thread_ = 0;
+  }
+  void Announce() {
+    if (tid_ == 0) return;  // no need to announce the main thread.
+    if (!announced_) {
+      announced_ = true;
+      Printf("Thread T%d created by T%d here:\n", tid_, parent_tid_);
+      stack_.PrintStack();
+    }
+  }
+  int tid() { return tid_; }
+  AsanThread *thread() { return thread_; }
+  void set_thread(AsanThread *thread) { thread_ = thread; }
+ private:
+  int tid_;
+  int parent_tid_;
+  bool announced_;
+  AsanStackTrace stack_;
+  AsanThread *thread_;
+};
+
+// AsanThread are stored in TSD and destroyed when the thread dies.
+class AsanThread {
+ public:
+  explicit AsanThread(LinkerInitialized);  // for T0.
+  AsanThread(int parent_tid, void *(*start_routine) (void *),
+             void *arg, AsanStackTrace *stack);
+  ~AsanThread();
+
+  void *ThreadStart();
+
+  uintptr_t stack_top() { return stack_top_; }
+  uintptr_t stack_bottom() { return stack_bottom_; }
+  size_t stack_size() { return stack_top_ - stack_bottom_; }
+  int tid() { return summary_->tid(); }
+  AsanThreadSummary *summary() { return summary_; }
+  void set_summary(AsanThreadSummary *summary) { summary_ = summary; }
+
+  const char *GetFrameNameByAddr(uintptr_t addr, uintptr_t *offset);
+
+  bool AddrIsInStack(uintptr_t addr) {
+    return addr >= stack_bottom_ && addr < stack_top_;
+  }
+
+  FakeStack &fake_stack() { return fake_stack_; }
+  AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
+  AsanStats &stats() { return stats_; }
+
+  static const int kInvalidTid = -1;
+
+ private:
+
+  void SetThreadStackTopAndBottom();
+  void ClearShadowForThreadStack();
+  AsanThreadSummary *summary_;
+  void *(*start_routine_) (void *param);
+  void *arg_;
+  uintptr_t  stack_top_;
+  uintptr_t  stack_bottom_;
+
+  FakeStack fake_stack_;
+  AsanThreadLocalMallocStorage malloc_storage_;
+  AsanStats stats_;
+};
+
+}  // namespace __asan
+
+#endif  // ASAN_THREAD_H

Added: compiler-rt/trunk/lib/asan/asan_thread_registry.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread_registry.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread_registry.cc (added)
+++ compiler-rt/trunk/lib/asan/asan_thread_registry.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,221 @@
+//===-- asan_thread_registry.cc ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// AsanThreadRegistry-related code. AsanThreadRegistry is a container
+// for summaries of all created threads.
+//===----------------------------------------------------------------------===//
+
+#include "asan_stack.h"
+#include "asan_thread.h"
+#include "asan_thread_registry.h"
+
+#include <limits.h>
+
+namespace __asan {
+
+static AsanThreadRegistry asan_thread_registry(__asan::LINKER_INITIALIZED);
+
+AsanThreadRegistry &asanThreadRegistry() {
+  return asan_thread_registry;
+}
+
+// Dark magic below. In order to be able to notice that we're not handling
+// some thread creation routines (e.g. on Mac OS) we want to distinguish the
+// thread that used to have a corresponding AsanThread object from the thread
+// that never had one. That's why upon AsanThread destruction we set the
+// pthread_key value to some odd number (that's not a valid pointer), instead
+// of NULL.
+// Because the TSD destructor for a non-NULL key value is called iteratively,
+// we increase the value by two, keeping it an invalid pointer.
+// Because the TSD implementations are allowed to call such a destructor
+// infinitely (see
+// http://pubs.opengroup.org/onlinepubs/009604499/functions/pthread_key_create.html
+// ), we exit the program after a certain number of iterations.
+static void DestroyAsanTsd(void *tsd) {
+  intptr_t iter = (intptr_t)tsd;
+  if (iter % 2 == 0) {
+    // The pointer is valid.
+    AsanThread *t = (AsanThread*)tsd;
+    if (t != asanThreadRegistry().GetMain()) {
+      delete t;
+    }
+    iter = 1;
+  } else {
+    // The pointer is invalid -- we've already destroyed the TSD before.
+    // If |iter| is too big, we're in the infinite loop. This should be
+    // impossible on the systems AddressSanitizer was tested on.
+    CHECK(iter < 4 * PTHREAD_DESTRUCTOR_ITERATIONS);
+    iter += 2;
+  }
+  CHECK(0 == pthread_setspecific(asanThreadRegistry().GetTlsKey(),
+                                 (void*)iter));
+  if (FLAG_v >= 2) {
+    Report("DestroyAsanTsd: writing %p to the TSD slot of thread %p\n",
+           (void*)iter, pthread_self());
+  }
+}
+
+AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
+    : main_thread_(x),
+      main_thread_summary_(x),
+      accumulated_stats_(x),
+      mu_(x) { }
+
+void AsanThreadRegistry::Init() {
+  CHECK(0 == pthread_key_create(&tls_key_, DestroyAsanTsd));
+  tls_key_created_ = true;
+  SetCurrent(&main_thread_);
+  main_thread_.set_summary(&main_thread_summary_);
+  main_thread_summary_.set_thread(&main_thread_);
+  thread_summaries_[0] = &main_thread_summary_;
+  n_threads_ = 1;
+}
+
+void AsanThreadRegistry::RegisterThread(AsanThread *thread, int parent_tid,
+                                        AsanStackTrace *stack) {
+  ScopedLock lock(&mu_);
+  CHECK(n_threads_ > 0);
+  int tid = n_threads_;
+  n_threads_++;
+  CHECK(n_threads_ < kMaxNumberOfThreads);
+  AsanThreadSummary *summary = new AsanThreadSummary(tid, parent_tid, stack);
+  summary->set_thread(thread);
+  thread_summaries_[tid] = summary;
+  thread->set_summary(summary);
+}
+
+void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
+  ScopedLock lock(&mu_);
+  FlushToAccumulatedStatsUnlocked(&thread->stats());
+  AsanThreadSummary *summary = thread->summary();
+  CHECK(summary);
+  summary->set_thread(NULL);
+}
+
+AsanThread *AsanThreadRegistry::GetMain() {
+  return &main_thread_;
+}
+
+AsanThread *AsanThreadRegistry::GetCurrent() {
+  CHECK(tls_key_created_);
+  AsanThread *thread = (AsanThread*)pthread_getspecific(tls_key_);
+  if ((!thread || (intptr_t)thread % 2) && FLAG_v >= 2) {
+    Report("GetCurrent: %p for thread %p\n", thread, pthread_self());
+  }
+  if ((intptr_t)thread % 2) {
+    // Invalid pointer -- we've deleted the AsanThread already. Return NULL as
+    // if the TSD was empty.
+    // TODO(glider): if the code in the client TSD destructor calls
+    // pthread_create(), we'll set the parent tid of the spawned thread to NULL,
+    // although the creation stack will belong to the current thread. This may
+    // confuse the user, but is quite unlikely.
+    return NULL;
+  } else {
+    // NULL or valid pointer to AsanThread.
+    return thread;
+  }
+}
+
+void AsanThreadRegistry::SetCurrent(AsanThread *t) {
+  if (FLAG_v >=2) {
+    Report("SetCurrent: %p for thread %p\n", t, pthread_self());
+  }
+  // Make sure we do not reset the current AsanThread.
+  intptr_t old_key = (intptr_t)pthread_getspecific(tls_key_);
+  CHECK(!old_key || old_key % 2);
+  CHECK(0 == pthread_setspecific(tls_key_, t));
+  CHECK(pthread_getspecific(tls_key_) == t);
+}
+
+pthread_key_t AsanThreadRegistry::GetTlsKey() {
+  return tls_key_;
+}
+
+// Returns true iff DestroyAsanTsd() was already called for this thread.
+bool AsanThreadRegistry::IsCurrentThreadDying() {
+  CHECK(tls_key_created_);
+  intptr_t thread = (intptr_t)pthread_getspecific(tls_key_);
+  return (bool)(thread % 2);
+}
+
+AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
+  AsanThread *t = GetCurrent();
+  return (t) ? t->stats() : main_thread_.stats();
+}
+
+AsanStats AsanThreadRegistry::GetAccumulatedStats() {
+  ScopedLock lock(&mu_);
+  UpdateAccumulatedStatsUnlocked();
+  return accumulated_stats_;
+}
+
+size_t AsanThreadRegistry::GetCurrentAllocatedBytes() {
+  ScopedLock lock(&mu_);
+  UpdateAccumulatedStatsUnlocked();
+  return accumulated_stats_.malloced - accumulated_stats_.freed;
+}
+
+size_t AsanThreadRegistry::GetHeapSize() {
+  ScopedLock lock(&mu_);
+  UpdateAccumulatedStatsUnlocked();
+  return accumulated_stats_.mmaped;
+}
+
+size_t AsanThreadRegistry::GetFreeBytes() {
+  ScopedLock lock(&mu_);
+  UpdateAccumulatedStatsUnlocked();
+  return accumulated_stats_.mmaped
+         - accumulated_stats_.malloced
+         - accumulated_stats_.malloced_redzones
+         + accumulated_stats_.really_freed
+         + accumulated_stats_.really_freed_redzones;
+}
+
+AsanThreadSummary *AsanThreadRegistry::FindByTid(int tid) {
+  CHECK(tid >= 0);
+  CHECK(tid < n_threads_);
+  CHECK(thread_summaries_[tid]);
+  return thread_summaries_[tid];
+}
+
+AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) {
+  ScopedLock lock(&mu_);
+  for (int tid = 0; tid < n_threads_; tid++) {
+    AsanThread *t = thread_summaries_[tid]->thread();
+    if (!t) continue;
+    if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
+      return t;
+    }
+  }
+  return 0;
+}
+
+void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
+  for (int tid = 0; tid < n_threads_; tid++) {
+    AsanThread *t = thread_summaries_[tid]->thread();
+    if (t != NULL) {
+      FlushToAccumulatedStatsUnlocked(&t->stats());
+    }
+  }
+}
+
+void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
+  // AsanStats consists of variables of type size_t only.
+  size_t *dst = (size_t*)&accumulated_stats_;
+  size_t *src = (size_t*)stats;
+  size_t num_fields = sizeof(AsanStats) / sizeof(size_t);
+  for (size_t i = 0; i < num_fields; i++) {
+    dst[i] += src[i];
+    src[i] = 0;
+  }
+}
+
+}  // namespace __asan

Added: compiler-rt/trunk/lib/asan/asan_thread_registry.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_thread_registry.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_thread_registry.h (added)
+++ compiler-rt/trunk/lib/asan/asan_thread_registry.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,88 @@
+//===-- asan_thread_registry.h ----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_thread_registry.cc
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_THREAD_REGISTRY_H
+#define ASAN_THREAD_REGISTRY_H
+
+#include "asan_lock.h"
+#include "asan_stack.h"
+#include "asan_stats.h"
+#include "asan_thread.h"
+
+namespace __asan {
+
+// Stores summaries of all created threads, returns current thread,
+// thread by tid, thread by stack address. There is a single instance
+// of AsanThreadRegistry for the whole program.
+// AsanThreadRegistry is thread-safe.
+class AsanThreadRegistry {
+ public:
+  explicit AsanThreadRegistry(LinkerInitialized);
+  void Init();
+  void RegisterThread(AsanThread *thread, int parent_tid,
+                      AsanStackTrace *stack);
+  void UnregisterThread(AsanThread *thread);
+
+  AsanThread *GetMain();
+  // Get the current thread. May return NULL.
+  AsanThread *GetCurrent();
+  void SetCurrent(AsanThread *t);
+  pthread_key_t GetTlsKey();
+  bool IsCurrentThreadDying();
+
+  int GetCurrentTidOrMinusOne() {
+    AsanThread *t = GetCurrent();
+    return t ? t->tid() : -1;
+  }
+
+  // Returns stats for GetCurrent(), or stats for
+  // T0 if GetCurrent() returns NULL.
+  AsanStats &GetCurrentThreadStats();
+  // Flushes all thread-local stats to accumulated stats, and returns
+  // a copy of accumulated stats.
+  AsanStats GetAccumulatedStats();
+  size_t GetCurrentAllocatedBytes();
+  size_t GetHeapSize();
+  size_t GetFreeBytes();
+
+  AsanThreadSummary *FindByTid(int tid);
+  AsanThread *FindThreadByStackAddress(uintptr_t addr);
+
+ private:
+  void UpdateAccumulatedStatsUnlocked();
+  // Adds values of all counters in "stats" to accumulated stats,
+  // and fills "stats" with zeroes.
+  void FlushToAccumulatedStatsUnlocked(AsanStats *stats);
+
+  static const int kMaxNumberOfThreads = (1 << 22);  // 4M
+  AsanThreadSummary *thread_summaries_[kMaxNumberOfThreads];
+  AsanThread main_thread_;
+  AsanThreadSummary main_thread_summary_;
+  AsanStats accumulated_stats_;
+  int n_threads_;
+  AsanLock mu_;
+  // For each thread tls_key_ stores the pointer to the corresponding
+  // AsanThread.
+  pthread_key_t tls_key_;
+  // This flag is updated only once at program startup, and then read
+  // by concurrent threads.
+  bool tls_key_created_;
+};
+
+// Returns a single instance of registry.
+AsanThreadRegistry &asanThreadRegistry();
+
+}  // namespace __asan
+
+#endif  // ASAN_THREAD_REGISTRY_H

Added: compiler-rt/trunk/lib/asan/mach_override/mach_override.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/mach_override/mach_override.c?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/mach_override/mach_override.c (added)
+++ compiler-rt/trunk/lib/asan/mach_override/mach_override.c Tue Nov 29 19:07:02 2011
@@ -0,0 +1,771 @@
+/*******************************************************************************
+	mach_override.c
+		Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+		Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
+	***************************************************************************/
+
+#include "mach_override.h"
+
+#include <mach-o/dyld.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <mach/vm_map.h>
+#include <sys/mman.h>
+
+#include <CoreServices/CoreServices.h>
+
+//#define DEBUG_DISASM 1
+#undef DEBUG_DISASM
+
+/**************************
+*	
+*	Constants
+*	
+**************************/
+#pragma mark	-
+#pragma mark	(Constants)
+
+#if defined(__ppc__) || defined(__POWERPC__)
+
+long kIslandTemplate[] = {
+	0x9001FFFC,	//	stw		r0,-4(SP)
+	0x3C00DEAD,	//	lis		r0,0xDEAD
+	0x6000BEEF,	//	ori		r0,r0,0xBEEF
+	0x7C0903A6,	//	mtctr	r0
+	0x8001FFFC,	//	lwz		r0,-4(SP)
+	0x60000000,	//	nop		; optionally replaced
+	0x4E800420 	//	bctr
+};
+
+#define kAddressHi			3
+#define kAddressLo			5
+#define kInstructionHi		10
+#define kInstructionLo		11
+
+#elif defined(__i386__) 
+
+#define kOriginalInstructionsSize 16
+
+char kIslandTemplate[] = {
+	// kOriginalInstructionsSize nop instructions so that we 
+	// should have enough space to host original instructions 
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	// Now the real jump instruction
+	0xE9, 0xEF, 0xBE, 0xAD, 0xDE
+};
+
+#define kInstructions	0
+#define kJumpAddress    kInstructions + kOriginalInstructionsSize + 1
+#elif defined(__x86_64__)
+
+#define kOriginalInstructionsSize 32
+
+#define kJumpAddress    kOriginalInstructionsSize + 6
+
+char kIslandTemplate[] = {
+	// kOriginalInstructionsSize nop instructions so that we 
+	// should have enough space to host original instructions 
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 
+	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+	// Now the real jump instruction
+	0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+};
+
+#endif
+
+#define	kAllocateHigh		1
+#define	kAllocateNormal		0
+
+/**************************
+*	
+*	Data Types
+*	
+**************************/
+#pragma mark	-
+#pragma mark	(Data Types)
+
+typedef	struct	{
+	char	instructions[sizeof(kIslandTemplate)];
+	int		allocatedHigh;
+}	BranchIsland;
+
+/**************************
+*	
+*	Funky Protos
+*	
+**************************/
+#pragma mark	-
+#pragma mark	(Funky Protos)
+
+	mach_error_t
+allocateBranchIsland(
+		BranchIsland	**island,
+		int				allocateHigh,
+		void *originalFunctionAddress);
+
+	mach_error_t
+freeBranchIsland(
+		BranchIsland	*island );
+
+#if defined(__ppc__) || defined(__POWERPC__)
+	mach_error_t
+setBranchIslandTarget(
+		BranchIsland	*island,
+		const void		*branchTo,
+		long			instruction );
+#endif 
+
+#if defined(__i386__) || defined(__x86_64__)
+mach_error_t
+setBranchIslandTarget_i386(
+						   BranchIsland	*island,
+						   const void		*branchTo,
+						   char*			instructions );
+void 
+atomic_mov64(
+		uint64_t *targetAddress,
+		uint64_t value );
+
+	static Boolean 
+eatKnownInstructions( 
+	unsigned char	*code, 
+	uint64_t		*newInstruction,
+	int				*howManyEaten, 
+	char			*originalInstructions );
+#endif
+
+/*******************************************************************************
+*	
+*	Interface
+*	
+*******************************************************************************/
+#pragma mark	-
+#pragma mark	(Interface)
+
+#if defined(__x86_64__)
+mach_error_t makeIslandExecutable(void *address) {
+	mach_error_t err = err_none;
+    vm_size_t pageSize;
+    host_page_size( mach_host_self(), &pageSize );
+    uint64_t page = (uint64_t)address & ~(uint64_t)(pageSize-1);
+    int e = err_none;
+    e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
+    e |= msync((void *)page, pageSize, MS_INVALIDATE );
+    if (e) {
+        err = err_cannot_override;
+    }
+    return err;
+}
+#endif
+
+    mach_error_t
+mach_override_ptr(
+	void *originalFunctionAddress,
+    const void *overrideFunctionAddress,
+    void **originalFunctionReentryIsland )
+{
+	assert( originalFunctionAddress );
+	assert( overrideFunctionAddress );
+
+	long	*originalFunctionPtr = (long*) originalFunctionAddress;
+#ifdef DEBUG_DISASM
+  {
+    fprintf(stderr, "Replacing function at %p\n", originalFunctionAddress);
+    fprintf(stderr, "First 16 bytes of the function: ");
+    unsigned char *orig = (unsigned char *)originalFunctionAddress;
+    int i;
+    for (i = 0; i < 16; i++) {
+       fprintf(stderr, "%x ", (unsigned int) orig[i]);
+    }
+    fprintf(stderr, "\n");
+    fprintf(stderr,
+            "To disassemble, save the following function as disas.c"
+            " and run:\n  gcc -c disas.c && gobjdump -d disas.o\n"
+            "The first 16 bytes of the original function will start"
+            " after four nop instructions.\n");
+    fprintf(stderr, "\nvoid foo() {\n  asm volatile(\"nop;nop;nop;nop;\");\n");
+    int j = 0;
+    for (j = 0; j < 2; j++) {
+      fprintf(stderr, "  asm volatile(\".byte ");
+      for (i = 8 * j; i < 8 * (j+1) - 1; i++) {
+        fprintf(stderr, "0x%x, ", (unsigned int) orig[i]);
+      }
+      fprintf(stderr, "0x%x;\");\n", (unsigned int) orig[8 * (j+1) - 1]);
+    }
+    fprintf(stderr, "}\n\n");
+  }
+#endif
+
+	mach_error_t	err = err_none;
+	
+#if defined(__ppc__) || defined(__POWERPC__)
+	//	Ensure first instruction isn't 'mfctr'.
+	#define	kMFCTRMask			0xfc1fffff
+	#define	kMFCTRInstruction	0x7c0903a6
+	
+	long	originalInstruction = *originalFunctionPtr;
+	if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
+		err = err_cannot_override;
+#elif defined(__i386__) || defined(__x86_64__)
+	int eatenCount = 0;
+	char originalInstructions[kOriginalInstructionsSize];
+	uint64_t jumpRelativeInstruction = 0; // JMP
+
+	Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr, 
+										&jumpRelativeInstruction, &eatenCount, originalInstructions);
+#ifdef DEBUG_DISASM
+  if (!overridePossible) fprintf(stderr, "overridePossible = false @%d\n", __LINE__);
+#endif
+	if (eatenCount > kOriginalInstructionsSize) {
+#ifdef DEBUG_DISASM
+		fprintf(stderr, "Too many instructions eaten\n");
+#endif    
+		overridePossible = false;
+	}
+	if (!overridePossible) err = err_cannot_override;
+	if (err) printf("err = %x %d\n", err, __LINE__);
+#endif
+	
+	//	Make the original function implementation writable.
+	if( !err ) {
+		err = vm_protect( mach_task_self(),
+				(vm_address_t) originalFunctionPtr,
+				sizeof(long), false, (VM_PROT_ALL | VM_PROT_COPY) );
+		if( err )
+			err = vm_protect( mach_task_self(),
+					(vm_address_t) originalFunctionPtr, sizeof(long), false,
+					(VM_PROT_DEFAULT | VM_PROT_COPY) );
+	}
+	if (err) printf("err = %x %d\n", err, __LINE__);
+	
+	//	Allocate and target the escape island to the overriding function.
+	BranchIsland	*escapeIsland = NULL;
+	if( !err )	
+		err = allocateBranchIsland( &escapeIsland, kAllocateHigh, originalFunctionAddress );
+		if (err) printf("err = %x %d\n", err, __LINE__);
+
+	
+#if defined(__ppc__) || defined(__POWERPC__)
+	if( !err )
+		err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
+	
+	//	Build the branch absolute instruction to the escape island.
+	long	branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
+	if( !err ) {
+		long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
+		branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
+	}
+#elif defined(__i386__) || defined(__x86_64__)
+        if (err) printf("err = %x %d\n", err, __LINE__);
+
+	if( !err )
+		err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
+ 
+	if (err) printf("err = %x %d\n", err, __LINE__);
+	// Build the jump relative instruction to the escape island
+#endif
+
+
+#if defined(__i386__) || defined(__x86_64__)
+	if (!err) {
+		uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
+		addressOffset = OSSwapInt32(addressOffset);
+		
+		jumpRelativeInstruction |= 0xE900000000000000LL; 
+		jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
+		jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);		
+	}
+#endif
+	
+	//	Optionally allocate & return the reentry island.
+	BranchIsland	*reentryIsland = NULL;
+	if( !err && originalFunctionReentryIsland ) {
+		err = allocateBranchIsland( &reentryIsland, kAllocateNormal, NULL);
+		if( !err )
+			*originalFunctionReentryIsland = reentryIsland;
+	}
+	
+#if defined(__ppc__) || defined(__POWERPC__)	
+	//	Atomically:
+	//	o If the reentry island was allocated:
+	//		o Insert the original instruction into the reentry island.
+	//		o Target the reentry island at the 2nd instruction of the
+	//		  original function.
+	//	o Replace the original instruction with the branch absolute.
+	if( !err ) {
+		int escapeIslandEngaged = false;
+		do {
+			if( reentryIsland )
+				err = setBranchIslandTarget( reentryIsland,
+						(void*) (originalFunctionPtr+1), originalInstruction );
+			if( !err ) {
+				escapeIslandEngaged = CompareAndSwap( originalInstruction,
+										branchAbsoluteInstruction,
+										(UInt32*)originalFunctionPtr );
+				if( !escapeIslandEngaged ) {
+					//	Someone replaced the instruction out from under us,
+					//	re-read the instruction, make sure it's still not
+					//	'mfctr' and try again.
+					originalInstruction = *originalFunctionPtr;
+					if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
+						err = err_cannot_override;
+				}
+			}
+		} while( !err && !escapeIslandEngaged );
+	}
+#elif defined(__i386__) || defined(__x86_64__)
+	// Atomically:
+	//	o If the reentry island was allocated:
+	//		o Insert the original instructions into the reentry island.
+	//		o Target the reentry island at the first non-replaced 
+	//        instruction of the original function.
+	//	o Replace the original first instructions with the jump relative.
+	//
+	// Note that on i386, we do not support someone else changing the code under our feet
+	if ( !err ) {
+		if( reentryIsland )
+			err = setBranchIslandTarget_i386( reentryIsland,
+										 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
+		if ( !err )
+			atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
+	}
+#endif
+	
+	//	Clean up on error.
+	if( err ) {
+		if( reentryIsland )
+			freeBranchIsland( reentryIsland );
+		if( escapeIsland )
+			freeBranchIsland( escapeIsland );
+	}
+
+#if defined(__x86_64__)
+        err = makeIslandExecutable(escapeIsland);
+        err = makeIslandExecutable(reentryIsland);
+#endif
+#ifdef DEBUG_DISASM
+  {
+    fprintf(stderr, "First 16 bytes of the function after slicing: ");
+    unsigned char *orig = (unsigned char *)originalFunctionAddress;
+    int i;
+    for (i = 0; i < 16; i++) {
+       fprintf(stderr, "%x ", (unsigned int) orig[i]);
+    }
+    fprintf(stderr, "\n");
+  }
+#endif
+
+	return err;
+}
+
+/*******************************************************************************
+*	
+*	Implementation
+*	
+*******************************************************************************/
+#pragma mark	-
+#pragma mark	(Implementation)
+
+/***************************************************************************//**
+	Implementation: Allocates memory for a branch island.
+	
+	@param	island			<-	The allocated island.
+	@param	allocateHigh	->	Whether to allocate the island at the end of the
+								address space (for use with the branch absolute
+								instruction).
+	@result					<-	mach_error_t
+
+	***************************************************************************/
+
+	mach_error_t
+allocateBranchIsland(
+		BranchIsland	**island,
+		int				allocateHigh,
+		void *originalFunctionAddress)
+{
+	assert( island );
+	
+	mach_error_t	err = err_none;
+	
+	if( allocateHigh ) {
+		vm_size_t pageSize;
+		err = host_page_size( mach_host_self(), &pageSize );
+		if( !err ) {
+			assert( sizeof( BranchIsland ) <= pageSize );
+#if defined(__x86_64__)
+			vm_address_t first = (uint64_t)originalFunctionAddress & ~(uint64_t)(((uint64_t)1 << 31) - 1) | ((uint64_t)1 << 31); // start in the middle of the page?
+			vm_address_t last = 0x0;
+#else
+			vm_address_t first = 0xfeffffff;
+			vm_address_t last = 0xfe000000 + pageSize;
+#endif
+
+			vm_address_t page = first;
+			int allocated = 0;
+			vm_map_t task_self = mach_task_self();
+			
+			while( !err && !allocated && page != last ) {
+
+				err = vm_allocate( task_self, &page, pageSize, 0 );
+				if( err == err_none )
+					allocated = 1;
+				else if( err == KERN_NO_SPACE ) {
+#if defined(__x86_64__)
+					page -= pageSize;
+#else
+					page += pageSize;
+#endif
+					err = err_none;
+				}
+			}
+			if( allocated )
+				*island = (BranchIsland*) page;
+			else if( !allocated && !err )
+				err = KERN_NO_SPACE;
+		}
+	} else {
+		void *block = malloc( sizeof( BranchIsland ) );
+		if( block )
+			*island = (BranchIsland*)block;
+		else
+			err = KERN_NO_SPACE;
+	}
+	if( !err )
+		(**island).allocatedHigh = allocateHigh;
+	
+	return err;
+}
+
+/***************************************************************************//**
+	Implementation: Deallocates memory for a branch island.
+	
+	@param	island	->	The island to deallocate.
+	@result			<-	mach_error_t
+
+	***************************************************************************/
+
+	mach_error_t
+freeBranchIsland(
+		BranchIsland	*island )
+{
+	assert( island );
+	assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
+	assert( island->allocatedHigh );
+	
+	mach_error_t	err = err_none;
+	
+	if( island->allocatedHigh ) {
+		vm_size_t pageSize;
+		err = host_page_size( mach_host_self(), &pageSize );
+		if( !err ) {
+			assert( sizeof( BranchIsland ) <= pageSize );
+			err = vm_deallocate(
+					mach_task_self(),
+					(vm_address_t) island, pageSize );
+		}
+	} else {
+		free( island );
+	}
+	
+	return err;
+}
+
+/***************************************************************************//**
+	Implementation: Sets the branch island's target, with an optional
+	instruction.
+	
+	@param	island		->	The branch island to insert target into.
+	@param	branchTo	->	The address of the target.
+	@param	instruction	->	Optional instruction to execute prior to branch. Set
+							to zero for nop.
+	@result				<-	mach_error_t
+
+	***************************************************************************/
+#if defined(__ppc__) || defined(__POWERPC__)
+	mach_error_t
+setBranchIslandTarget(
+		BranchIsland	*island,
+		const void		*branchTo,
+		long			instruction )
+{
+	//	Copy over the template code.
+    bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
+    
+    //	Fill in the address.
+    ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
+    ((short*)island->instructions)[kAddressHi]
+    	= (((long) branchTo) >> 16) & 0x0000FFFF;
+    
+    //	Fill in the (optional) instuction.
+    if( instruction != 0 ) {
+        ((short*)island->instructions)[kInstructionLo]
+        	= instruction & 0x0000FFFF;
+        ((short*)island->instructions)[kInstructionHi]
+        	= (instruction >> 16) & 0x0000FFFF;
+    }
+    
+    //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
+	msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
+    
+    return err_none;
+}
+#endif 
+
+#if defined(__i386__)
+	mach_error_t
+setBranchIslandTarget_i386(
+	BranchIsland	*island,
+	const void		*branchTo,
+	char*			instructions )
+{
+
+	//	Copy over the template code.
+    bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
+
+	// copy original instructions
+	if (instructions) {
+		bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
+	}
+	
+    // Fill in the address.
+    int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
+    *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset; 
+
+    msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
+    return err_none;
+}
+
+#elif defined(__x86_64__)
+mach_error_t
+setBranchIslandTarget_i386(
+        BranchIsland	*island,
+        const void		*branchTo,
+        char*			instructions )
+{
+    // Copy over the template code.
+    bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
+
+    // Copy original instructions.
+    if (instructions) {
+        bcopy (instructions, island->instructions, kOriginalInstructionsSize);
+    }
+
+    //	Fill in the address.
+    *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo; 
+    msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
+
+    return err_none;
+}
+#endif
+
+
+#if defined(__i386__) || defined(__x86_64__)
+// simplistic instruction matching
+typedef struct {
+	unsigned int length; // max 15
+	unsigned char mask[15]; // sequence of bytes in memory order
+	unsigned char constraint[15]; // sequence of bytes in memory order
+}	AsmInstructionMatch;
+
+#if defined(__i386__)
+static AsmInstructionMatch possibleInstructions[] = {
+	{ 0x1, {0xFF}, {0x90} },							// nop
+	{ 0x1, {0xFF}, {0x55} },							// push %esp
+	{ 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },				                // mov %esp,%ebp
+	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x89, 0x1C, 0x24} },				                // mov %ebx,(%esp)
+	{ 0x1, {0xFF}, {0x53} },							// push %ebx
+	{ 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },	                        // sub 0x??, %esp
+	{ 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} },	// sub 0x??, %esp with 32bit immediate
+	{ 0x1, {0xFF}, {0x57} },							// push %edi
+	{ 0x1, {0xFF}, {0x56} },							// push %esi
+	{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },						// xor %eax, %eax
+	{ 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} },  // mov $imm(%ebp), %reg
+	{ 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} },  // mov $imm(%eax-%edx), %reg
+        { 0x4, {0xFF, 0x00, 0x00, 0x00}, {0x8B, 0x00, 0x00, 0x00} },  // mov r16,r/m16 or r32,r/m32
+        { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB9, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %ecx
+  { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
+        { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },             // pxor xmm2/128, xmm1
+        { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, // fninit
+	{ 0x0 }
+};
+#elif defined(__x86_64__)
+// TODO(glider): disassembling the "0x48, 0x89" sequences is trickier than it's done below.
+// If it stops working, refer to http://ref.x86asm.net/geek.html#modrm_byte_32_64 to do it
+// more accurately.
+static AsmInstructionMatch possibleInstructions[] = {
+	{ 0x1, {0xFF}, {0x90} },							// nop
+	{ 0x1, {0xF8}, {0x50} },							// push %rX
+  { 0x1, {0xFF}, {0x65} },              // GS prefix
+	{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },				// mov %rsp,%rbp
+	{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },	                // sub 0x??, %rsp
+	{ 0x4, {0xFB, 0xFF, 0x07, 0x00}, {0x48, 0x89, 0x05, 0x00} },	                // move onto rbp
+	{ 0x3, {0xFB, 0xFF, 0x00}, {0x48, 0x89, 0x00} },	                            // mov %reg, %reg
+	{ 0x2, {0xFF, 0x00}, {0x41, 0x00} },						// push %rXX
+	{ 0x2, {0xFF, 0x00}, {0x85, 0x00} },						// test %rX,%rX
+	{ 0x2, {0xFF, 0x00}, {0x77, 0x00} },						// ja $i8
+	{ 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },        // mov $imm, %reg
+  { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0x25, 0x00, 0x00, 0x00, 0x00} },  // and $imm, %eax
+
+  { 0x8, {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
+         {0x48, 0x8B, 0x34, 0x25, 0x00, 0x00, 0x00, 0x00}, },                     // mov $imm, %rsi
+  { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xFA, 0x00}, },   // cmp $i8, %rdx
+	{ 0xa, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               {0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },    // mov $imm, %rax
+        { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
+               {0x81, 0xE6, 0x00, 0x00, 0x00, 0x00} },                            // and $imm, %esi
+        { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} },              // pxor xmm2/128, xmm1
+        { 0x2, {0xFF, 0x00}, {0x89, 0x00} },                               // mov r/m32,r32 or r/m16,r16
+        { 0x3, {0xFF, 0xFF, 0xFF}, {0x49, 0x89, 0xF8} },                   // mov %rdi,%r8        
+        { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} },  // pushq $imm(%rdi)
+        { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, // fninit
+	{ 0x0 }
+};
+#endif
+
+static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
+{
+	Boolean match = true;
+	size_t i;
+  assert(instruction);
+#ifdef DEBUG_DISASM
+  fprintf(stderr, "Matching: ");
+#endif  
+	for (i=0; i<instruction->length; i++) {
+		unsigned char mask = instruction->mask[i];
+		unsigned char constraint = instruction->constraint[i];
+		unsigned char codeValue = code[i];
+#ifdef DEBUG_DISASM
+    fprintf(stderr, "%x ", (unsigned)codeValue);
+#endif    
+		match = ((codeValue & mask) == constraint);
+		if (!match) break;
+	}
+#ifdef DEBUG_DISASM
+  if (match) {
+    fprintf(stderr, " OK\n");
+  } else {
+    fprintf(stderr, " FAIL\n");
+  }
+#endif  
+	return match;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+	static Boolean 
+eatKnownInstructions( 
+	unsigned char *code, 
+	uint64_t* newInstruction,
+	int* howManyEaten, 
+	char* originalInstructions )
+{
+	Boolean allInstructionsKnown = true;
+	int totalEaten = 0;
+	unsigned char* ptr = code;
+	int remainsToEat = 5; // a JMP instruction takes 5 bytes
+	
+	if (howManyEaten) *howManyEaten = 0;
+	while (remainsToEat > 0) {
+		Boolean curInstructionKnown = false;
+		
+		// See if instruction matches one  we know
+		AsmInstructionMatch* curInstr = possibleInstructions;
+		do { 
+			if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
+			curInstr++;
+		} while (curInstr->length > 0);
+		
+		// if all instruction matches failed, we don't know current instruction then, stop here
+		if (!curInstructionKnown) { 
+			allInstructionsKnown = false;
+			break;
+		}
+		
+		// At this point, we've matched curInstr
+		int eaten = curInstr->length;
+		ptr += eaten;
+		remainsToEat -= eaten;
+		totalEaten += eaten;
+	}
+
+
+	if (howManyEaten) *howManyEaten = totalEaten;
+
+	if (originalInstructions) {
+		Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
+		
+		if (enoughSpaceForOriginalInstructions) {
+			memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
+			bcopy(code, originalInstructions, totalEaten);
+		} else {
+#ifdef DEBUG_DISASM    
+			fprintf (stderr, "Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
+#endif      
+			return false;
+		}
+	}
+	
+	if (allInstructionsKnown) {
+		// save last 3 bytes of first 64bits of codre we'll replace
+		uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
+		currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
+		currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL; 
+		
+		// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
+		*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
+		*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
+	}
+
+	return allInstructionsKnown;
+}
+#endif
+
+#if defined(__i386__)
+__asm(
+			".text;"
+			".align 2, 0x90;"
+			"_atomic_mov64:;"
+			"	pushl %ebp;"
+			"	movl %esp, %ebp;"
+			"	pushl %esi;"
+			"	pushl %ebx;"
+			"	pushl %ecx;"
+			"	pushl %eax;"
+			"	pushl %edx;"
+	
+			// atomic push of value to an address
+			// we use cmpxchg8b, which compares content of an address with 
+			// edx:eax. If they are equal, it atomically puts 64bit value 
+			// ecx:ebx in address. 
+			// We thus put contents of address in edx:eax to force ecx:ebx
+			// in address
+			"	mov		8(%ebp), %esi;"  // esi contains target address
+			"	mov		12(%ebp), %ebx;"
+			"	mov		16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
+			"	mov		(%esi), %eax;"
+			"	mov		4(%esi), %edx;"  // edx:eax now contains value currently contained in target address
+			"	lock; cmpxchg8b	(%esi);" // atomic move.
+			
+			// restore registers
+			"	popl %edx;"
+			"	popl %eax;"
+			"	popl %ecx;"
+			"	popl %ebx;"
+			"	popl %esi;"
+			"	popl %ebp;"
+			"	ret"
+);
+#elif defined(__x86_64__)
+void atomic_mov64(
+		uint64_t *targetAddress,
+		uint64_t value )
+{
+    *targetAddress = value;
+}
+#endif
+#endif

Added: compiler-rt/trunk/lib/asan/mach_override/mach_override.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/mach_override/mach_override.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/mach_override/mach_override.h (added)
+++ compiler-rt/trunk/lib/asan/mach_override/mach_override.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,121 @@
+/*******************************************************************************
+	mach_override.h
+		Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+		Some rights reserved: <http://opensource.org/licenses/mit-license.php>
+
+	***************************************************************************/
+
+/***************************************************************************//**
+	@mainpage	mach_override
+	@author		Jonathan 'Wolf' Rentzsch: <http://rentzsch.com>
+	
+	This package, coded in C to the Mach API, allows you to override ("patch")
+	program- and system-supplied functions at runtime. You can fully replace
+	functions with your implementations, or merely head- or tail-patch the
+	original implementations.
+	
+	Use it by #include'ing mach_override.h from your .c, .m or .mm file(s).
+	
+	@todo	Discontinue use of Carbon's MakeDataExecutable() and
+			CompareAndSwap() calls and start using the Mach equivalents, if they
+			exist. If they don't, write them and roll them in. That way, this
+			code will be pure Mach, which will make it easier to use everywhere.
+			Update: MakeDataExecutable() has been replaced by
+			msync(MS_INVALIDATE). There is an OSCompareAndSwap in libkern, but
+			I'm currently unsure if I can link against it. May have to roll in
+			my own version...
+	@todo	Stop using an entire 4K high-allocated VM page per 28-byte escape
+			branch island. Done right, this will dramatically speed up escape
+			island allocations when they number over 250. Then again, if you're
+			overriding more than 250 functions, maybe speed isn't your main
+			concern...
+	@todo	Add detection of: b, bl, bla, bc, bcl, bcla, bcctrl, bclrl
+			first-instructions. Initially, we should refuse to override
+			functions beginning with these instructions. Eventually, we should
+			dynamically rewrite them to make them position-independent.
+	@todo	Write mach_unoverride(), which would remove an override placed on a
+			function. Must be multiple-override aware, which means an almost
+			complete rewrite under the covers, because the target address can't
+			be spread across two load instructions like it is now since it will
+			need to be atomically updatable.
+	@todo	Add non-rentry variants of overrides to test_mach_override.
+
+	***************************************************************************/
+
+#ifndef		_mach_override_
+#define		_mach_override_
+
+#include <sys/types.h>
+#include <mach/error.h>
+
+#ifdef	__cplusplus
+	extern	"C"	{
+#endif
+
+/**
+	Returned if the function to be overrided begins with a 'mfctr' instruction.
+*/
+#define	err_cannot_override	(err_local|1)
+
+/************************************************************************************//**
+	Dynamically overrides the function implementation referenced by
+	originalFunctionAddress with the implentation pointed to by overrideFunctionAddress.
+	Optionally returns a pointer to a "reentry island" which, if jumped to, will resume
+	the original implementation.
+	
+	@param	originalFunctionAddress			->	Required address of the function to
+												override (with overrideFunctionAddress).
+	@param	overrideFunctionAddress			->	Required address to the overriding
+												function.
+	@param	originalFunctionReentryIsland	<-	Optional pointer to pointer to the
+												reentry island. Can be NULL.
+	@result									<-	err_cannot_override if the original
+												function's implementation begins with
+												the 'mfctr' instruction.
+
+	************************************************************************************/
+
+    mach_error_t
+mach_override_ptr(
+	void *originalFunctionAddress,
+    const void *overrideFunctionAddress,
+    void **originalFunctionReentryIsland );
+
+/************************************************************************************//**
+	
+
+	************************************************************************************/
+ 
+#ifdef	__cplusplus
+
+#define MACH_OVERRIDE( ORIGINAL_FUNCTION_RETURN_TYPE, ORIGINAL_FUNCTION_NAME, ORIGINAL_FUNCTION_ARGS, ERR )			\
+	{																												\
+		static ORIGINAL_FUNCTION_RETURN_TYPE (*ORIGINAL_FUNCTION_NAME##_reenter)ORIGINAL_FUNCTION_ARGS;				\
+		static bool ORIGINAL_FUNCTION_NAME##_overriden = false;														\
+		class mach_override_class__##ORIGINAL_FUNCTION_NAME {														\
+		public:																										\
+			static kern_return_t override(void *originalFunctionPtr) {												\
+				kern_return_t result = err_none;																	\
+				if (!ORIGINAL_FUNCTION_NAME##_overriden) {															\
+					ORIGINAL_FUNCTION_NAME##_overriden = true;														\
+					result = mach_override_ptr( (void*)originalFunctionPtr,											\
+												(void*)mach_override_class__##ORIGINAL_FUNCTION_NAME::replacement,	\
+												(void**)&ORIGINAL_FUNCTION_NAME##_reenter );						\
+				}																									\
+				return result;																						\
+			}																										\
+			static ORIGINAL_FUNCTION_RETURN_TYPE replacement ORIGINAL_FUNCTION_ARGS {
+
+#define END_MACH_OVERRIDE( ORIGINAL_FUNCTION_NAME )																	\
+			}																										\
+		};																											\
+																													\
+		err = mach_override_class__##ORIGINAL_FUNCTION_NAME::override((void*)ORIGINAL_FUNCTION_NAME);				\
+	}
+ 
+#endif
+
+#ifdef	__cplusplus
+	}
+#endif
+#endif	//	_mach_override_

Added: compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py (added)
+++ compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py Tue Nov 29 19:07:02 2011
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+#===- lib/asan/scripts/asan_symbolize.py -----------------------------------===#
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+import os
+import re
+import sys
+import string
+import subprocess
+
+pipes = {}
+
+def patch_address(frameno, addr_s):
+  ''' Subtracts 1 or 2 from the top frame's address.
+  Top frame is normally the return address from asan_report*
+  call, which is not expected to return at all. Because of that, this
+  address often belongs to the next source code line, or even to a different
+  function. '''
+  if frameno == '0':
+    addr = int(addr_s, 16)
+    if os.uname()[4].startswith('arm'):
+      # Cancel the Thumb bit
+      addr = addr & (~1)
+    addr -= 1
+    return hex(addr)
+  return addr_s
+
+# TODO(glider): need some refactoring here
+def symbolize_addr2line(line):
+  #0 0x7f6e35cf2e45  (/blah/foo.so+0x11fe45)
+  match = re.match('^( *#([0-9]+) *0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line)
+  if match:
+    frameno = match.group(2)
+    binary = match.group(3)
+    addr = match.group(4)
+    addr = patch_address(frameno, addr)
+    if not pipes.has_key(binary):
+      pipes[binary] = subprocess.Popen(["addr2line", "-f", "-e", binary],
+                         stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+    p = pipes[binary]
+    try:
+      print >>p.stdin, addr
+      function_name = p.stdout.readline().rstrip()
+      file_name     = p.stdout.readline().rstrip()
+    except:
+      function_name = ""
+      file_name = ""
+    for path_to_cut in sys.argv[1:]:
+      file_name = re.sub(".*" + path_to_cut, "", file_name)
+    file_name = re.sub(".*asan_[a-z_]*.cc:[0-9]*", "_asan_rtl_", file_name)
+    file_name = re.sub(".*crtstuff.c:0", "???:0", file_name)
+
+    print match.group(1), "in", function_name, file_name
+  else:
+    print line.rstrip()
+
+def symbolize_atos(line):
+  #0 0x7f6e35cf2e45  (/blah/foo.so+0x11fe45)
+  match = re.match('^( *#([0-9]+) *)(0x[0-9a-f]+) *\((.*)\+(0x[0-9a-f]+)\)', line)
+  if match:
+    #print line
+    prefix = match.group(1)
+    frameno = match.group(2)
+    addr = match.group(3)
+    binary = match.group(4)
+    offset = match.group(5)
+    addr = patch_address(frameno, addr)
+    load_addr = int(addr, 16) - int(offset, 16)
+    if not pipes.has_key(binary):
+      #print "atos -o %s -l %s" % (binary, hex(load_addr))
+      pipes[binary] = subprocess.Popen(["atos", "-o", binary],
+                         stdin=subprocess.PIPE, stdout=subprocess.PIPE,)
+    p = pipes[binary]
+    # TODO(glider): how to tell if the address is absolute?
+    if ".app/" in binary and not ".framework" in binary:
+      print >>p.stdin, "%s" % addr
+    else:
+      print >>p.stdin, "%s" % offset
+    # TODO(glider): it's more efficient to make a batch atos run for each binary.
+    p.stdin.close()
+    atos_line = p.stdout.readline().rstrip()
+    del pipes[binary]
+
+    print "%s%s in %s" % (prefix, addr, atos_line)
+  else:
+    print line.rstrip()
+
+system = os.uname()[0]
+if system in ['Linux', 'Darwin']:
+  for line in sys.stdin:
+    if system == 'Linux':
+      symbolize_addr2line(line)
+    elif system == 'Darwin':
+      symbolize_atos(line)
+else:
+  print 'Unknown system: ', system

Propchange: compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py
------------------------------------------------------------------------------
    svn:executable = *

Added: compiler-rt/trunk/lib/asan/sysinfo/basictypes.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/sysinfo/basictypes.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/sysinfo/basictypes.h (added)
+++ compiler-rt/trunk/lib/asan/sysinfo/basictypes.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,321 @@
+// Copyright (c) 2005, Google Inc.
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// 
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef _BASICTYPES_H_
+#define _BASICTYPES_H_
+
+#include <inttypes.h>           // uint16_t might be here; PRId64 too.
+#include <stdint.h>             // to get uint16_t (ISO naming madness)
+#include <sys/types.h>          // our last best hope for uint16_t
+
+// Standard typedefs
+// All Google code is compiled with -funsigned-char to make "char"
+// unsigned.  Google code therefore doesn't need a "uchar" type.
+// TODO(csilvers): how do we make sure unsigned-char works on non-gcc systems?
+typedef signed char         schar;
+typedef int8_t              int8;
+typedef int16_t             int16;
+typedef int32_t             int32;
+typedef int64_t             int64;
+
+// NOTE: unsigned types are DANGEROUS in loops and other arithmetical
+// places.  Use the signed types unless your variable represents a bit
+// pattern (eg a hash value) or you really need the extra bit.  Do NOT
+// use 'unsigned' to express "this value should always be positive";
+// use assertions for this.
+
+typedef uint8_t            uint8;
+typedef uint16_t           uint16;
+typedef uint32_t           uint32;
+typedef uint64_t           uint64;
+
+const uint16 kuint16max = (   (uint16) 0xFFFF);
+const uint32 kuint32max = (   (uint32) 0xFFFFFFFF);
+const uint64 kuint64max = ( (((uint64) kuint32max) << 32) | kuint32max );
+
+const  int8  kint8max   = (   (  int8) 0x7F);
+const  int16 kint16max  = (   ( int16) 0x7FFF);
+const  int32 kint32max  = (   ( int32) 0x7FFFFFFF);
+const  int64 kint64max =  ( ((( int64) kint32max) << 32) | kuint32max );
+
+const  int8  kint8min   = (   (  int8) 0x80);
+const  int16 kint16min  = (   ( int16) 0x8000);
+const  int32 kint32min  = (   ( int32) 0x80000000);
+const  int64 kint64min =  ( ((( int64) kint32min) << 32) | 0 );
+
+// Define the "portable" printf and scanf macros, if they're not
+// already there (via the inttypes.h we #included above, hopefully).
+// Mostly it's old systems that don't support inttypes.h, so we assume
+// they're 32 bit.
+#ifndef PRIx64
+#define PRIx64 "llx"
+#endif
+#ifndef SCNx64
+#define SCNx64 "llx"
+#endif
+#ifndef PRId64
+#define PRId64 "lld"
+#endif
+#ifndef SCNd64
+#define SCNd64 "lld"
+#endif
+#ifndef PRIu64
+#define PRIu64 "llu"
+#endif
+#ifndef PRIxPTR
+#define PRIxPTR "lx"
+#endif
+
+// Also allow for printing of a pthread_t.
+#define GPRIuPTHREAD "lu"
+#define GPRIxPTHREAD "lx"
+#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__)
+#define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast<uintptr_t>(pthreadt)
+#else
+#define PRINTABLE_PTHREAD(pthreadt) pthreadt
+#endif
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName)    \
+  TypeName(const TypeName&);                    \
+  void operator=(const TypeName&)
+
+// An alternate name that leaves out the moral judgment... :-)
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) DISALLOW_EVIL_CONSTRUCTORS(TypeName)
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   COMPILE_ASSERT(sizeof(num_content_type_names) == sizeof(int),
+//                  content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+//
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+//   elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+//     #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+//   does not work, as gcc supports variable-length arrays whose sizes
+//   are determined at run-time (this is gcc's extension and not part
+//   of the C++ standard).  As a result, gcc fails to reject the
+//   following code with the simple definition:
+//
+//     int foo;
+//     COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+//                               // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+//   expr is a compile-time constant.  (Template arguments must be
+//   determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+//   to work around a bug in gcc 3.4.4 and 4.0.1.  If we had written
+//
+//     CompileAssert<bool(expr)>
+//
+//   instead, these compilers will refuse to compile
+//
+//     COMPILE_ASSERT(5 > 0, some_message);
+//
+//   (They seem to think the ">" in "5 > 0" marks the end of the
+//   template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+//     ((expr) ? 1 : -1).
+//
+//   This is to avoid running into a bug in MS VC 7.1, which
+//   causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+template <bool>
+struct CompileAssert {
+};
+
+#define COMPILE_ASSERT(expr, msg)                               \
+  typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+#define arraysize(a)  (sizeof(a) / sizeof(*(a)))
+
+#define OFFSETOF_MEMBER(strct, field)                                   \
+   (reinterpret_cast<char*>(&reinterpret_cast<strct*>(16)->field) -     \
+    reinterpret_cast<char*>(16))
+
+#ifdef HAVE___ATTRIBUTE__
+# define ATTRIBUTE_WEAK      __attribute__((weak))
+# define ATTRIBUTE_NOINLINE  __attribute__((noinline))
+#else
+# define ATTRIBUTE_WEAK
+# define ATTRIBUTE_NOINLINE
+#endif
+
+// Section attributes are supported for both ELF and Mach-O, but in
+// very different ways.  Here's the API we provide:
+// 1) ATTRIBUTE_SECTION: put this with the declaration of all functions
+//    you want to be in the same linker section
+// 2) DEFINE_ATTRIBUTE_SECTION_VARS: must be called once per unique
+//    name.  You want to make sure this is executed before any
+//    DECLARE_ATTRIBUTE_SECTION_VARS; the easiest way is to put them
+//    in the same .cc file.  Put this call at the global level.
+// 3) INIT_ATTRIBUTE_SECTION_VARS: you can scatter calls to this in
+//    multiple places to help ensure execution before any
+//    DECLARE_ATTRIBUTE_SECTION_VARS.  You must have at least one
+//    DEFINE, but you can have many INITs.  Put each in its own scope.
+// 4) DECLARE_ATTRIBUTE_SECTION_VARS: must be called before using
+//    ATTRIBUTE_SECTION_START or ATTRIBUTE_SECTION_STOP on a name.
+//    Put this call at the global level.
+// 5) ATTRIBUTE_SECTION_START/ATTRIBUTE_SECTION_STOP: call this to say
+//    where in memory a given section is.  All functions declared with
+//    ATTRIBUTE_SECTION are guaranteed to be between START and STOP.
+
+#if defined(HAVE___ATTRIBUTE__) && defined(__ELF__)
+# define ATTRIBUTE_SECTION(name) __attribute__ ((section (#name)))
+
+  // Weak section declaration to be used as a global declaration
+  // for ATTRIBUTE_SECTION_START|STOP(name) to compile and link
+  // even without functions with ATTRIBUTE_SECTION(name).
+# define DECLARE_ATTRIBUTE_SECTION_VARS(name) \
+    extern char __start_##name[] ATTRIBUTE_WEAK; \
+    extern char __stop_##name[] ATTRIBUTE_WEAK
+# define INIT_ATTRIBUTE_SECTION_VARS(name)     // no-op for ELF
+# define DEFINE_ATTRIBUTE_SECTION_VARS(name)   // no-op for ELF
+
+  // Return void* pointers to start/end of a section of code with functions
+  // having ATTRIBUTE_SECTION(name), or 0 if no such function exists.
+  // One must DECLARE_ATTRIBUTE_SECTION(name) for this to compile and link.
+# define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(__start_##name))
+# define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(__stop_##name))
+# define HAVE_ATTRIBUTE_SECTION_START 1
+
+#elif defined(HAVE___ATTRIBUTE__) && defined(__MACH__)
+# define ATTRIBUTE_SECTION(name) __attribute__ ((section ("__TEXT, " #name)))
+
+#include <mach-o/getsect.h>
+#include <mach-o/dyld.h>
+class AssignAttributeStartEnd {
+ public:
+  AssignAttributeStartEnd(const char* name, char** pstart, char** pend) {
+    // Find out what dynamic library name is defined in
+    if (_dyld_present()) {
+      for (int i = _dyld_image_count() - 1; i >= 0; --i) {
+        const mach_header* hdr = _dyld_get_image_header(i);
+#ifdef MH_MAGIC_64
+        if (hdr->magic == MH_MAGIC_64) {
+          uint64_t len;
+          *pstart = getsectdatafromheader_64((mach_header_64*)hdr,
+                                             "__TEXT", name, &len);
+          if (*pstart) {   // NULL if not defined in this dynamic library
+            *pstart += _dyld_get_image_vmaddr_slide(i);   // correct for reloc
+            *pend = *pstart + len;
+            return;
+          }
+        }
+#endif
+        if (hdr->magic == MH_MAGIC) {
+          uint32_t len;
+          *pstart = getsectdatafromheader(hdr, "__TEXT", name, &len);
+          if (*pstart) {   // NULL if not defined in this dynamic library
+            *pstart += _dyld_get_image_vmaddr_slide(i);   // correct for reloc
+            *pend = *pstart + len;
+            return;
+          }
+        }
+      }
+    }
+    // If we get here, not defined in a dll at all.  See if defined statically.
+    unsigned long len;    // don't ask me why this type isn't uint32_t too...
+    *pstart = getsectdata("__TEXT", name, &len);
+    *pend = *pstart + len;
+  }
+};
+
+#define DECLARE_ATTRIBUTE_SECTION_VARS(name)    \
+  extern char* __start_##name;                  \
+  extern char* __stop_##name
+
+#define INIT_ATTRIBUTE_SECTION_VARS(name)               \
+  DECLARE_ATTRIBUTE_SECTION_VARS(name);                 \
+  static const AssignAttributeStartEnd __assign_##name( \
+    #name, &__start_##name, &__stop_##name)
+
+#define DEFINE_ATTRIBUTE_SECTION_VARS(name)     \
+  char* __start_##name, *__stop_##name;         \
+  INIT_ATTRIBUTE_SECTION_VARS(name)
+
+# define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(__start_##name))
+# define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(__stop_##name))
+# define HAVE_ATTRIBUTE_SECTION_START 1
+
+#else  // not HAVE___ATTRIBUTE__ && __ELF__, nor HAVE___ATTRIBUTE__ && __MACH__
+# define ATTRIBUTE_SECTION(name)
+# define DECLARE_ATTRIBUTE_SECTION_VARS(name)
+# define INIT_ATTRIBUTE_SECTION_VARS(name)
+# define DEFINE_ATTRIBUTE_SECTION_VARS(name)
+# define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(0))
+# define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(0))
+
+#endif  // HAVE___ATTRIBUTE__ and __ELF__ or __MACH__
+
+#if defined(HAVE___ATTRIBUTE__) && (defined(__i386__) || defined(__x86_64__))
+# define CACHELINE_SIZE 64
+# define CACHELINE_ALIGNED __attribute__((aligned(CACHELINE_SIZE)))
+#else
+# define CACHELINE_ALIGNED
+#endif  // defined(HAVE___ATTRIBUTE__) && (__i386__ || __x86_64__)
+
+
+// The following enum should be used only as a constructor argument to indicate
+// that the variable has static storage class, and that the constructor should
+// do nothing to its state.  It indicates to the reader that it is legal to
+// declare a static nistance of the class, provided the constructor is given
+// the base::LINKER_INITIALIZED argument.  Normally, it is unsafe to declare a
+// static variable that has a constructor or a destructor because invocation
+// order is undefined.  However, IF the type can be initialized by filling with
+// zeroes (which the loader does for static variables), AND the destructor also
+// does nothing to the storage, then a constructor declared as
+//       explicit MyClass(base::LinkerInitialized x) {}
+// and invoked as
+//       static MyClass my_variable_name(base::LINKER_INITIALIZED);
+namespace base {
+enum LinkerInitialized { LINKER_INITIALIZED };
+}
+
+#endif  // _BASICTYPES_H_

Added: compiler-rt/trunk/lib/asan/sysinfo/sysinfo.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/sysinfo/sysinfo.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/sysinfo/sysinfo.cc (added)
+++ compiler-rt/trunk/lib/asan/sysinfo/sysinfo.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,612 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// 
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <assert.h>
+#include <stdlib.h>   // for getenv()
+#include <stdio.h>    // for snprintf(), sscanf()
+#include <string.h>   // for memmove(), memchr(), etc.
+#include <fcntl.h>    // for open()
+#include <errno.h>    // for errno
+#include <unistd.h>   // for read()
+#if defined __MACH__          // Mac OS X, almost certainly
+#include <mach-o/dyld.h>      // for iterating over dll's in ProcMapsIter
+#include <mach-o/loader.h>    // for iterating over dll's in ProcMapsIter
+#include <sys/types.h>
+#include <sys/sysctl.h>       // how we figure out numcpu's on OS X
+#elif defined __FreeBSD__
+#include <sys/sysctl.h>
+#elif defined __sun__         // Solaris
+#include <procfs.h>           // for, e.g., prmap_t
+#elif defined(PLATFORM_WINDOWS)
+#include <process.h>          // for getpid() (actually, _getpid())
+#include <shlwapi.h>          // for SHGetValueA()
+#include <tlhelp32.h>         // for Module32First()
+#endif
+#include "sysinfo.h"
+
+#ifdef PLATFORM_WINDOWS
+#ifdef MODULEENTRY32
+// In a change from the usual W-A pattern, there is no A variant of
+// MODULEENTRY32.  Tlhelp32.h #defines the W variant, but not the A.
+// In unicode mode, tlhelp32.h #defines MODULEENTRY32 to be
+// MODULEENTRY32W.  These #undefs are the only way I see to get back
+// access to the original, ascii struct (and related functions).
+#undef MODULEENTRY32
+#undef Module32First
+#undef Module32Next
+#undef PMODULEENTRY32
+#undef LPMODULEENTRY32
+#endif  /* MODULEENTRY32 */
+// MinGW doesn't seem to define this, perhaps some windowsen don't either.
+#ifndef TH32CS_SNAPMODULE32
+#define TH32CS_SNAPMODULE32  0
+#endif  /* TH32CS_SNAPMODULE32 */
+#endif  /* PLATFORM_WINDOWS */
+
+// Re-run fn until it doesn't cause EINTR.
+#define NO_INTR(fn)  do {} while ((fn) < 0 && errno == EINTR)
+
+// open/read/close can set errno, which may be illegal at this
+// time, so prefer making the syscalls directly if we can.
+#ifdef HAVE_SYS_SYSCALL_H
+# include <sys/syscall.h>
+# define safeopen(filename, mode)  syscall(SYS_open, filename, mode)
+# define saferead(fd, buffer, size)  syscall(SYS_read, fd, buffer, size)
+# define safeclose(fd)  syscall(SYS_close, fd)
+#else
+# define safeopen(filename, mode)  open(filename, mode)
+# define saferead(fd, buffer, size)  read(fd, buffer, size)
+# define safeclose(fd)  close(fd)
+#endif
+
+
+// ----------------------------------------------------------------------
+// HasPosixThreads()
+//      Return true if we're running POSIX (e.g., NPTL on Linux)
+//      threads, as opposed to a non-POSIX thread libary.  The thing
+//      that we care about is whether a thread's pid is the same as
+//      the thread that spawned it.  If so, this function returns
+//      true.
+// ----------------------------------------------------------------------
+bool HasPosixThreads() {
+#if defined(__linux__) and !defined(ANDROID)
+#ifndef _CS_GNU_LIBPTHREAD_VERSION
+#define _CS_GNU_LIBPTHREAD_VERSION 3
+#endif
+  char buf[32];
+  //  We assume that, if confstr() doesn't know about this name, then
+  //  the same glibc is providing LinuxThreads.
+  if (confstr(_CS_GNU_LIBPTHREAD_VERSION, buf, sizeof(buf)) == 0)
+    return false;
+  return strncmp(buf, "NPTL", 4) == 0;
+#elif defined(PLATFORM_WINDOWS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+  return false;
+#else  // other OS
+  return true;      //  Assume that everything else has Posix
+#endif  // else OS_LINUX
+}
+
+// ----------------------------------------------------------------------
+
+#define CHECK_LT(x, y) do { assert((x) < (y)); } while (0)
+
+#if defined __linux__ || defined __FreeBSD__ || defined __sun__ || defined __CYGWIN__ || defined __CYGWIN32__
+static void ConstructFilename(const char* spec, pid_t pid,
+                              char* buf, int buf_size) {
+  CHECK_LT(snprintf(buf, buf_size,
+                    spec,
+                    static_cast<int>(pid ? pid : getpid())), buf_size);
+}
+#endif
+
+// A templatized helper function instantiated for Mach (OS X) only.
+// It can handle finding info for both 32 bits and 64 bits.
+// Returns true if it successfully handled the hdr, false else.
+#ifdef __MACH__          // Mac OS X, almost certainly
+template<uint32_t kMagic, uint32_t kLCSegment,
+         typename MachHeader, typename SegmentCommand>
+static bool NextExtMachHelper(const mach_header* hdr,
+                              int current_image, int current_load_cmd,
+                              uint64 *start, uint64 *end, char **flags,
+                              uint64 *offset, int64 *inode, char **filename,
+                              uint64 *file_mapping, uint64 *file_pages,
+                              uint64 *anon_mapping, uint64 *anon_pages,
+                              dev_t *dev) {
+  static char kDefaultPerms[5] = "r-xp";
+  if (hdr->magic != kMagic)
+    return false;
+  const char* lc = (const char *)hdr + sizeof(MachHeader);
+  // TODO(csilvers): make this not-quadradic (increment and hold state)
+  for (int j = 0; j < current_load_cmd; j++)  // advance to *our* load_cmd
+    lc += ((const load_command *)lc)->cmdsize;
+  if (((const load_command *)lc)->cmd == kLCSegment) {
+    const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image);
+    const SegmentCommand* sc = (const SegmentCommand *)lc;
+    if (start) *start = sc->vmaddr + dlloff;
+    if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
+    if (flags) *flags = kDefaultPerms;  // can we do better?
+    if (offset) *offset = sc->fileoff;
+    if (inode) *inode = 0;
+    if (filename)
+      *filename = const_cast<char*>(_dyld_get_image_name(current_image));
+    if (file_mapping) *file_mapping = 0;
+    if (file_pages) *file_pages = 0;   // could we use sc->filesize?
+    if (anon_mapping) *anon_mapping = 0;
+    if (anon_pages) *anon_pages = 0;
+    if (dev) *dev = 0;
+    return true;
+  }
+
+  return false;
+}
+#endif
+
+ProcMapsIterator::ProcMapsIterator(pid_t pid) {
+  Init(pid, NULL, false);
+}
+
+ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer) {
+  Init(pid, buffer, false);
+}
+
+ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer *buffer,
+                                   bool use_maps_backing) {
+  Init(pid, buffer, use_maps_backing);
+}
+
+void ProcMapsIterator::Init(pid_t pid, Buffer *buffer,
+                            bool use_maps_backing) {
+  pid_ = pid;
+  using_maps_backing_ = use_maps_backing;
+  dynamic_buffer_ = NULL;
+  if (!buffer) {
+    // If the user didn't pass in any buffer storage, allocate it
+    // now. This is the normal case; the signal handler passes in a
+    // static buffer.
+    buffer = dynamic_buffer_ = new Buffer;
+  } else {
+    dynamic_buffer_ = NULL;
+  }
+
+  ibuf_ = buffer->buf_;
+
+  stext_ = etext_ = nextline_ = ibuf_;
+  ebuf_ = ibuf_ + Buffer::kBufSize - 1;
+  nextline_ = ibuf_;
+
+#if defined(__linux__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+  if (use_maps_backing) {  // don't bother with clever "self" stuff in this case
+    ConstructFilename("/proc/%d/maps_backing", pid, ibuf_, Buffer::kBufSize);
+  } else if (pid == 0) {
+    // We have to kludge a bit to deal with the args ConstructFilename
+    // expects.  The 1 is never used -- it's only impt. that it's not 0.
+    ConstructFilename("/proc/self/maps", 1, ibuf_, Buffer::kBufSize);
+  } else {
+    ConstructFilename("/proc/%d/maps", pid, ibuf_, Buffer::kBufSize);
+  }
+  // No error logging since this can be called from the crash dump
+  // handler at awkward moments. Users should call Valid() before
+  // using.
+  NO_INTR(fd_ = open(ibuf_, O_RDONLY));
+#elif defined(__FreeBSD__)
+  // We don't support maps_backing on freebsd
+  if (pid == 0) {
+    ConstructFilename("/proc/curproc/map", 1, ibuf_, Buffer::kBufSize);
+  } else {
+    ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize);
+  }
+  NO_INTR(fd_ = open(ibuf_, O_RDONLY));
+#elif defined(__sun__)
+  if (pid == 0) {
+    ConstructFilename("/proc/self/map", 1, ibuf_, Buffer::kBufSize);
+  } else {
+    ConstructFilename("/proc/%d/map", pid, ibuf_, Buffer::kBufSize);
+  }
+  NO_INTR(fd_ = open(ibuf_, O_RDONLY));
+#elif defined(__MACH__)
+  current_image_ = _dyld_image_count();   // count down from the top
+  current_load_cmd_ = -1;
+#elif defined(PLATFORM_WINDOWS)
+  snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE |
+                                       TH32CS_SNAPMODULE32,
+                                       GetCurrentProcessId());
+  memset(&module_, 0, sizeof(module_));
+#else
+  fd_ = -1;   // so Valid() is always false
+#endif
+
+}
+
+ProcMapsIterator::~ProcMapsIterator() {
+#if defined(PLATFORM_WINDOWS)
+  if (snapshot_ != INVALID_HANDLE_VALUE) CloseHandle(snapshot_);
+#elif defined(__MACH__)
+  // no cleanup necessary!
+#else
+  if (fd_ >= 0) NO_INTR(close(fd_));
+#endif
+  delete dynamic_buffer_;
+}
+
+bool ProcMapsIterator::Valid() const {
+#if defined(PLATFORM_WINDOWS)
+  return snapshot_ != INVALID_HANDLE_VALUE;
+#elif defined(__MACH__)
+  return 1;
+#else
+  return fd_ != -1;
+#endif
+}
+
+bool ProcMapsIterator::Next(uint64 *start, uint64 *end, char **flags,
+                            uint64 *offset, int64 *inode, char **filename) {
+  return NextExt(start, end, flags, offset, inode, filename, NULL, NULL,
+                 NULL, NULL, NULL);
+}
+
+// This has too many arguments.  It should really be building
+// a map object and returning it.  The problem is that this is called
+// when the memory allocator state is undefined, hence the arguments.
+bool ProcMapsIterator::NextExt(uint64 *start, uint64 *end, char **flags,
+                               uint64 *offset, int64 *inode, char **filename,
+                               uint64 *file_mapping, uint64 *file_pages,
+                               uint64 *anon_mapping, uint64 *anon_pages,
+                               dev_t *dev) {
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
+  do {
+    // Advance to the start of the next line
+    stext_ = nextline_;
+
+    // See if we have a complete line in the buffer already
+    nextline_ = static_cast<char *>(memchr (stext_, '\n', etext_ - stext_));
+    if (!nextline_) {
+      // Shift/fill the buffer so we do have a line
+      int count = etext_ - stext_;
+
+      // Move the current text to the start of the buffer
+      memmove(ibuf_, stext_, count);
+      stext_ = ibuf_;
+      etext_ = ibuf_ + count;
+
+      int nread = 0;            // fill up buffer with text
+      while (etext_ < ebuf_) {
+        NO_INTR(nread = read(fd_, etext_, ebuf_ - etext_));
+        if (nread > 0)
+          etext_ += nread;
+        else
+          break;
+      }
+
+      // Zero out remaining characters in buffer at EOF to avoid returning
+      // garbage from subsequent calls.
+      if (etext_ != ebuf_ && nread == 0) {
+        memset(etext_, 0, ebuf_ - etext_);
+      }
+      *etext_ = '\n';   // sentinel; safe because ibuf extends 1 char beyond ebuf
+      nextline_ = static_cast<char *>(memchr (stext_, '\n', etext_ + 1 - stext_));
+    }
+    *nextline_ = 0;                // turn newline into nul
+    nextline_ += ((nextline_ < etext_)? 1 : 0);  // skip nul if not end of text
+    // stext_ now points at a nul-terminated line
+    uint64 tmpstart, tmpend, tmpoffset;
+    int64 tmpinode;
+    int major, minor;
+    unsigned filename_offset = 0;
+#if defined(__linux__)
+    // for now, assume all linuxes have the same format
+    if (sscanf(stext_, "%"SCNx64"-%"SCNx64" %4s %"SCNx64" %x:%x %"SCNd64" %n",
+               start ? start : &tmpstart,
+               end ? end : &tmpend,
+               flags_,
+               offset ? offset : &tmpoffset,
+               &major, &minor,
+               inode ? inode : &tmpinode, &filename_offset) != 7) continue;
+#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
+    // cygwin is like linux, except the third field is the "entry point"
+    // rather than the offset (see format_process_maps at
+    // http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/fhandler_process.cc?rev=1.89&content-type=text/x-cvsweb-markup&cvsroot=src
+    // Offset is always be 0 on cygwin: cygwin implements an mmap
+    // by loading the whole file and then calling NtMapViewOfSection.
+    // Cygwin also seems to set its flags kinda randomly; use windows default.
+    char tmpflags[5];
+    if (offset)
+      *offset = 0;
+    strcpy(flags_, "r-xp");
+    if (sscanf(stext_, "%llx-%llx %4s %llx %x:%x %lld %n",
+               start ? start : &tmpstart,
+               end ? end : &tmpend,
+               tmpflags,
+               &tmpoffset,
+               &major, &minor,
+               inode ? inode : &tmpinode, &filename_offset) != 7) continue;
+#elif defined(__FreeBSD__)
+    // For the format, see http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/fs/procfs/procfs_map.c?rev=1.31&content-type=text/x-cvsweb-markup
+    tmpstart = tmpend = tmpoffset = 0;
+    tmpinode = 0;
+    major = minor = 0;   // can't get this info in freebsd
+    if (inode)
+      *inode = 0;        // nor this
+    if (offset)
+      *offset = 0;       // seems like this should be in there, but maybe not
+    // start end resident privateresident obj(?) prot refcnt shadowcnt
+    // flags copy_on_write needs_copy type filename:
+    // 0x8048000 0x804a000 2 0 0xc104ce70 r-x 1 0 0x0 COW NC vnode /bin/cat
+    if (sscanf(stext_, "0x%"SCNx64" 0x%"SCNx64" %*d %*d %*p %3s %*d %*d 0x%*x %*s %*s %*s %n",
+               start ? start : &tmpstart,
+               end ? end : &tmpend,
+               flags_,
+               &filename_offset) != 3) continue;
+#endif
+
+    // Depending on the Linux kernel being used, there may or may not be a space
+    // after the inode if there is no filename.  sscanf will in such situations
+    // nondeterministically either fill in filename_offset or not (the results
+    // differ on multiple calls in the same run even with identical arguments).
+    // We don't want to wander off somewhere beyond the end of the string.
+    size_t stext_length = strlen(stext_);
+    if (filename_offset == 0 || filename_offset > stext_length)
+      filename_offset = stext_length;
+
+    // We found an entry
+    if (flags) *flags = flags_;
+    if (filename) *filename = stext_ + filename_offset;
+    if (dev) *dev = minor | (major << 8);
+
+    if (using_maps_backing_) {
+      // Extract and parse physical page backing info.
+      char *backing_ptr = stext_ + filename_offset +
+          strlen(stext_+filename_offset);
+
+      // find the second '('
+      int paren_count = 0;
+      while (--backing_ptr > stext_) {
+        if (*backing_ptr == '(') {
+          ++paren_count;
+          if (paren_count >= 2) {
+            uint64 tmp_file_mapping;
+            uint64 tmp_file_pages;
+            uint64 tmp_anon_mapping;
+            uint64 tmp_anon_pages;
+
+            sscanf(backing_ptr+1, "F %"SCNx64" %"SCNd64") (A %"SCNx64" %"SCNd64")",
+                   file_mapping ? file_mapping : &tmp_file_mapping,
+                   file_pages ? file_pages : &tmp_file_pages,
+                   anon_mapping ? anon_mapping : &tmp_anon_mapping,
+                   anon_pages ? anon_pages : &tmp_anon_pages);
+            // null terminate the file name (there is a space
+            // before the first (.
+            backing_ptr[-1] = 0;
+            break;
+          }
+        }
+      }
+    }
+
+    return true;
+  } while (etext_ > ibuf_);
+#elif defined(__sun__)
+  // This is based on MA_READ == 4, MA_WRITE == 2, MA_EXEC == 1
+  static char kPerms[8][4] = { "---", "--x", "-w-", "-wx",
+                               "r--", "r-x", "rw-", "rwx" };
+  COMPILE_ASSERT(MA_READ == 4, solaris_ma_read_must_equal_4);
+  COMPILE_ASSERT(MA_WRITE == 2, solaris_ma_write_must_equal_2);
+  COMPILE_ASSERT(MA_EXEC == 1, solaris_ma_exec_must_equal_1);
+  Buffer object_path;
+  int nread = 0;            // fill up buffer with text
+  NO_INTR(nread = read(fd_, ibuf_, sizeof(prmap_t)));
+  if (nread == sizeof(prmap_t)) {
+    long inode_from_mapname = 0;
+    prmap_t* mapinfo = reinterpret_cast<prmap_t*>(ibuf_);
+    // Best-effort attempt to get the inode from the filename.  I think the
+    // two middle ints are major and minor device numbers, but I'm not sure.
+    sscanf(mapinfo->pr_mapname, "ufs.%*d.%*d.%ld", &inode_from_mapname);
+
+    if (pid_ == 0) {
+      CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize,
+                        "/proc/self/path/%s", mapinfo->pr_mapname),
+               Buffer::kBufSize);
+    } else {
+      CHECK_LT(snprintf(object_path.buf_, Buffer::kBufSize,
+                        "/proc/%d/path/%s",
+                        static_cast<int>(pid_), mapinfo->pr_mapname),
+               Buffer::kBufSize);
+    }
+    ssize_t len = readlink(object_path.buf_, current_filename_, PATH_MAX);
+    CHECK_LT(len, PATH_MAX);
+    if (len < 0)
+      len = 0;
+    current_filename_[len] = '\0';
+
+    if (start) *start = mapinfo->pr_vaddr;
+    if (end) *end = mapinfo->pr_vaddr + mapinfo->pr_size;
+    if (flags) *flags = kPerms[mapinfo->pr_mflags & 7];
+    if (offset) *offset = mapinfo->pr_offset;
+    if (inode) *inode = inode_from_mapname;
+    if (filename) *filename = current_filename_;
+    if (file_mapping) *file_mapping = 0;
+    if (file_pages) *file_pages = 0;
+    if (anon_mapping) *anon_mapping = 0;
+    if (anon_pages) *anon_pages = 0;
+    if (dev) *dev = 0;
+    return true;
+  }
+#elif defined(__MACH__)
+  // We return a separate entry for each segment in the DLL. (TODO(csilvers):
+  // can we do better?)  A DLL ("image") has load-commands, some of which
+  // talk about segment boundaries.
+  // cf image_for_address from http://svn.digium.com/view/asterisk/team/oej/minivoicemail/dlfcn.c?revision=53912
+  for (; current_image_ >= 0; current_image_--) {
+    const mach_header* hdr = _dyld_get_image_header(current_image_);
+    if (!hdr) continue;
+    if (current_load_cmd_ < 0)   // set up for this image
+      current_load_cmd_ = hdr->ncmds;  // again, go from the top down
+
+    // We start with the next load command (we've already looked at this one).
+    for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) {
+#ifdef MH_MAGIC_64
+      if (NextExtMachHelper<MH_MAGIC_64, LC_SEGMENT_64,
+                            struct mach_header_64, struct segment_command_64>(
+                                hdr, current_image_, current_load_cmd_,
+                                start, end, flags, offset, inode, filename,
+                                file_mapping, file_pages, anon_mapping,
+                                anon_pages, dev)) {
+        return true;
+      }
+#endif
+      if (NextExtMachHelper<MH_MAGIC, LC_SEGMENT,
+                            struct mach_header, struct segment_command>(
+                                hdr, current_image_, current_load_cmd_,
+                                start, end, flags, offset, inode, filename,
+                                file_mapping, file_pages, anon_mapping,
+                                anon_pages, dev)) {
+        return true;
+      }
+    }
+    // If we get here, no more load_cmd's in this image talk about
+    // segments.  Go on to the next image.
+  }
+#elif defined(PLATFORM_WINDOWS)
+  static char kDefaultPerms[5] = "r-xp";
+  BOOL ok;
+  if (module_.dwSize == 0) {  // only possible before first call
+    module_.dwSize = sizeof(module_);
+    ok = Module32First(snapshot_, &module_);
+  } else {
+    ok = Module32Next(snapshot_, &module_);
+  }
+  if (ok) {
+    uint64 base_addr = reinterpret_cast<DWORD_PTR>(module_.modBaseAddr);
+    if (start) *start = base_addr;
+    if (end) *end = base_addr + module_.modBaseSize;
+    if (flags) *flags = kDefaultPerms;
+    if (offset) *offset = 0;
+    if (inode) *inode = 0;
+    if (filename) *filename = module_.szExePath;
+    if (file_mapping) *file_mapping = 0;
+    if (file_pages) *file_pages = 0;
+    if (anon_mapping) *anon_mapping = 0;
+    if (anon_pages) *anon_pages = 0;
+    if (dev) *dev = 0;
+    return true;
+  }
+#endif
+
+  // We didn't find anything
+  return false;
+}
+
+int ProcMapsIterator::FormatLine(char* buffer, int bufsize,
+                                 uint64 start, uint64 end, const char *flags,
+                                 uint64 offset, int64 inode,
+                                 const char *filename, dev_t dev) {
+  // We assume 'flags' looks like 'rwxp' or 'rwx'.
+  char r = (flags && flags[0] == 'r') ? 'r' : '-';
+  char w = (flags && flags[0] && flags[1] == 'w') ? 'w' : '-';
+  char x = (flags && flags[0] && flags[1] && flags[2] == 'x') ? 'x' : '-';
+  // p always seems set on linux, so we set the default to 'p', not '-'
+  char p = (flags && flags[0] && flags[1] && flags[2] && flags[3] != 'p')
+      ? '-' : 'p';
+
+  const int rc = snprintf(buffer, bufsize,
+                          "%08"PRIx64"-%08"PRIx64" %c%c%c%c %08"PRIx64" %02x:%02x %-11"PRId64" %s\n",
+                          start, end, r,w,x,p, offset,
+                          static_cast<int>(dev/256), static_cast<int>(dev%256),
+                          inode, filename);
+  return (rc < 0 || rc >= bufsize) ? 0 : rc;
+}
+
+// Helper to add the list of mapped shared libraries to a profile.
+// Fill formatted "/proc/self/maps" contents into buffer 'buf' of size 'size'
+// and return the actual size occupied in 'buf'.  We fill wrote_all to true
+// if we successfully wrote all proc lines to buf, false else.
+// We do not provision for 0-terminating 'buf'.
+int FillProcSelfMaps(char buf[], int size, bool* wrote_all) {
+  ProcMapsIterator::Buffer iterbuf;
+  ProcMapsIterator it(0, &iterbuf);   // 0 means "current pid"
+
+  uint64 start, end, offset;
+  int64 inode;
+  char *flags, *filename;
+  int bytes_written = 0;
+  *wrote_all = true;
+  while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) {
+    const int line_length = it.FormatLine(buf + bytes_written,
+                                          size - bytes_written,
+                                          start, end, flags, offset,
+                                          inode, filename, 0);
+    if (line_length == 0)
+      *wrote_all = false;     // failed to write this line out
+    else
+      bytes_written += line_length;
+
+  }
+  return bytes_written;
+}
+
+// Dump the same data as FillProcSelfMaps reads to fd.
+// It seems easier to repeat parts of FillProcSelfMaps here than to
+// reuse it via a call.
+void DumpProcSelfMaps(RawFD fd) {
+  ProcMapsIterator::Buffer iterbuf;
+  ProcMapsIterator it(0, &iterbuf);   // 0 means "current pid"
+
+  uint64 start, end, offset;
+  int64 inode;
+  char *flags, *filename;
+  ProcMapsIterator::Buffer linebuf;
+  while (it.Next(&start, &end, &flags, &offset, &inode, &filename)) {
+    int written = it.FormatLine(linebuf.buf_, sizeof(linebuf.buf_),
+                                start, end, flags, offset, inode, filename,
+                                0);
+    RawWrite(fd, linebuf.buf_, written);
+  }
+}
+
+// Re-run fn until it doesn't cause EINTR.
+#define NO_INTR(fn)  do {} while ((fn) < 0 && errno == EINTR)
+
+RawFD RawOpenForWriting(const char* filename) {
+  return open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0664);
+}
+
+void RawWrite(RawFD fd, const char* buf, size_t len) {
+  while (len > 0) {
+    ssize_t r;
+    NO_INTR(r = write(fd, buf, len));
+    if (r <= 0) break;
+    buf += r;
+    len -= r;
+  }
+}
+
+void RawClose(RawFD fd) {
+  NO_INTR(close(fd));
+}
+

Added: compiler-rt/trunk/lib/asan/sysinfo/sysinfo.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/sysinfo/sysinfo.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/sysinfo/sysinfo.h (added)
+++ compiler-rt/trunk/lib/asan/sysinfo/sysinfo.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,234 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// 
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// All functions here are thread-hostile due to file caching unless
+// commented otherwise.
+
+#ifndef _SYSINFO_H_
+#define _SYSINFO_H_
+
+#include <time.h>
+#if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__))
+#include <windows.h>   // for DWORD
+#include <TlHelp32.h>  // for CreateToolhelp32Snapshot
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>    // for pid_t
+#endif
+#include <stddef.h>    // for size_t
+#include <limits.h>    // for PATH_MAX
+#include "basictypes.h"
+
+// This getenv function is safe to call before the C runtime is initialized.
+// On Windows, it utilizes GetEnvironmentVariable() and on unix it uses
+// /proc/self/environ instead calling getenv().  It's intended to be used in
+// routines that run before main(), when the state required for getenv() may
+// not be set up yet.  In particular, errno isn't set up until relatively late
+// (after the pthreads library has a chance to make it threadsafe), and
+// getenv() doesn't work until then. 
+// On some platforms, this call will utilize the same, static buffer for
+// repeated GetenvBeforeMain() calls. Callers should not expect pointers from
+// this routine to be long lived.
+// Note that on unix, /proc only has the environment at the time the
+// application was started, so this routine ignores setenv() calls/etc.  Also
+// note it only reads the first 16K of the environment.
+extern const char* GetenvBeforeMain(const char* name);
+
+// This takes as an argument an environment-variable name (like
+// CPUPROFILE) whose value is supposed to be a file-path, and sets
+// path to that path, and returns true.  Non-trivial for surprising
+// reasons, as documented in sysinfo.cc.  path must have space PATH_MAX.
+extern bool GetUniquePathFromEnv(const char* env_name, char* path);
+
+extern int NumCPUs();
+
+// processor cycles per second of each processor.  Thread-safe.
+extern double CyclesPerSecond(void);
+
+
+//  Return true if we're running POSIX (e.g., NPTL on Linux) threads,
+//  as opposed to a non-POSIX thread libary.  The thing that we care
+//  about is whether a thread's pid is the same as the thread that
+//  spawned it.  If so, this function returns true.
+//  Thread-safe.
+//  Note: We consider false negatives to be OK.
+bool HasPosixThreads();
+
+#ifndef SWIG  // SWIG doesn't like struct Buffer and variable arguments.
+
+// A ProcMapsIterator abstracts access to /proc/maps for a given
+// process. Needs to be stack-allocatable and avoid using stdio/malloc
+// so it can be used in the google stack dumper, heap-profiler, etc.
+//
+// On Windows and Mac OS X, this iterator iterates *only* over DLLs
+// mapped into this process space.  For Linux, FreeBSD, and Solaris,
+// it iterates over *all* mapped memory regions, including anonymous
+// mmaps.  For other O/Ss, it is unlikely to work at all, and Valid()
+// will always return false.  Also note: this routine only works on
+// FreeBSD if procfs is mounted: make sure this is in your /etc/fstab:
+//    proc            /proc   procfs  rw 0 0
+class ProcMapsIterator {
+ public:
+  struct Buffer {
+#ifdef __FreeBSD__
+    // FreeBSD requires us to read all of the maps file at once, so
+    // we have to make a buffer that's "always" big enough
+    static const size_t kBufSize = 102400;
+#else   // a one-line buffer is good enough
+    static const size_t kBufSize = PATH_MAX + 1024;
+#endif
+    char buf_[kBufSize];
+  };
+
+
+  // Create a new iterator for the specified pid.  pid can be 0 for "self".
+  explicit ProcMapsIterator(pid_t pid);
+
+  // Create an iterator with specified storage (for use in signal
+  // handler). "buffer" should point to a ProcMapsIterator::Buffer
+  // buffer can be NULL in which case a bufer will be allocated.
+  ProcMapsIterator(pid_t pid, Buffer *buffer);
+
+  // Iterate through maps_backing instead of maps if use_maps_backing
+  // is true.  Otherwise the same as above.  buffer can be NULL and
+  // it will allocate a buffer itself.
+  ProcMapsIterator(pid_t pid, Buffer *buffer,
+                   bool use_maps_backing);
+
+  // Returns true if the iterator successfully initialized;
+  bool Valid() const;
+
+  // Returns a pointer to the most recently parsed line. Only valid
+  // after Next() returns true, and until the iterator is destroyed or
+  // Next() is called again.  This may give strange results on non-Linux
+  // systems.  Prefer FormatLine() if that may be a concern.
+  const char *CurrentLine() const { return stext_; }
+
+  // Writes the "canonical" form of the /proc/xxx/maps info for a single
+  // line to the passed-in buffer. Returns the number of bytes written,
+  // or 0 if it was not able to write the complete line.  (To guarantee
+  // success, buffer should have size at least Buffer::kBufSize.)
+  // Takes as arguments values set via a call to Next().  The
+  // "canonical" form of the line (taken from linux's /proc/xxx/maps):
+  //    <start_addr(hex)>-<end_addr(hex)> <perms(rwxp)> <offset(hex)>   +
+  //    <major_dev(hex)>:<minor_dev(hex)> <inode> <filename> Note: the
+  // eg
+  //    08048000-0804c000 r-xp 00000000 03:01 3793678    /bin/cat
+  // If you don't have the dev_t (dev), feel free to pass in 0.
+  // (Next() doesn't return a dev_t, though NextExt does.)
+  //
+  // Note: if filename and flags were obtained via a call to Next(),
+  // then the output of this function is only valid if Next() returned
+  // true, and only until the iterator is destroyed or Next() is
+  // called again.  (Since filename, at least, points into CurrentLine.)
+  static int FormatLine(char* buffer, int bufsize,
+                        uint64 start, uint64 end, const char *flags,
+                        uint64 offset, int64 inode, const char *filename,
+                        dev_t dev);
+
+  // Find the next entry in /proc/maps; return true if found or false
+  // if at the end of the file.
+  //
+  // Any of the result pointers can be NULL if you're not interested
+  // in those values.
+  //
+  // If "flags" and "filename" are passed, they end up pointing to
+  // storage within the ProcMapsIterator that is valid only until the
+  // iterator is destroyed or Next() is called again. The caller may
+  // modify the contents of these strings (up as far as the first NUL,
+  // and only until the subsequent call to Next()) if desired.
+
+  // The offsets are all uint64 in order to handle the case of a
+  // 32-bit process running on a 64-bit kernel
+  //
+  // IMPORTANT NOTE: see top-of-class notes for details about what
+  // mapped regions Next() iterates over, depending on O/S.
+  // TODO(csilvers): make flags and filename const.
+  bool Next(uint64 *start, uint64 *end, char **flags,
+            uint64 *offset, int64 *inode, char **filename);
+
+  bool NextExt(uint64 *start, uint64 *end, char **flags,
+               uint64 *offset, int64 *inode, char **filename,
+               uint64 *file_mapping, uint64 *file_pages,
+               uint64 *anon_mapping, uint64 *anon_pages,
+               dev_t *dev);
+
+  ~ProcMapsIterator();
+
+ private:
+  void Init(pid_t pid, Buffer *buffer, bool use_maps_backing);
+
+  char *ibuf_;        // input buffer
+  char *stext_;       // start of text
+  char *etext_;       // end of text
+  char *nextline_;    // start of next line
+  char *ebuf_;        // end of buffer (1 char for a nul)
+#if (defined(_WIN32) || defined(__MINGW32__)) && (!defined(__CYGWIN__) && !defined(__CYGWIN32__))
+  HANDLE snapshot_;   // filehandle on dll info
+  // In a change from the usual W-A pattern, there is no A variant of
+  // MODULEENTRY32.  Tlhelp32.h #defines the W variant, but not the A.
+  // We want the original A variants, and this #undef is the only
+  // way I see to get them.  Redefining it when we're done prevents us
+  // from affecting other .cc files.
+# ifdef MODULEENTRY32  // Alias of W
+#   undef MODULEENTRY32
+  MODULEENTRY32 module_;   // info about current dll (and dll iterator)
+#   define MODULEENTRY32 MODULEENTRY32W
+# else  // It's the ascii, the one we want.
+  MODULEENTRY32 module_;   // info about current dll (and dll iterator)
+# endif
+#elif defined(__MACH__)
+  int current_image_; // dll's are called "images" in macos parlance
+  int current_load_cmd_;   // the segment of this dll we're examining
+#elif defined(__sun__)     // Solaris
+  int fd_;
+  char current_filename_[PATH_MAX];
+#else
+  int fd_;            // filehandle on /proc/*/maps
+#endif
+  pid_t pid_;
+  char flags_[10];
+  Buffer* dynamic_buffer_;  // dynamically-allocated Buffer
+  bool using_maps_backing_; // true if we are looking at maps_backing instead of maps.
+};
+
+#endif  /* #ifndef SWIG */
+
+// Helper routines
+typedef int RawFD;
+const RawFD kIllegalRawFD = -1;   // what open returns if it fails
+
+RawFD RawOpenForWriting(const char* filename);   // uses default permissions
+void RawWrite(RawFD fd, const char* buf, size_t len);
+void RawClose(RawFD fd);
+
+int FillProcSelfMaps(char buf[], int size, bool* wrote_all);
+void DumpProcSelfMaps(RawFD fd);
+
+#endif   /* #ifndef _SYSINFO_H_ */

Added: compiler-rt/trunk/lib/asan/tests/asan_benchmarks_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_benchmarks_test.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_benchmarks_test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_benchmarks_test.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,77 @@
+//===-- asan_benchmarks_test.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some benchmarks for the instrumented code.
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_config.h"
+#include "asan_test_utils.h"
+
+template<class T>
+__attribute__((noinline))
+static void ManyAccessFunc(T *x, size_t n_elements, size_t n_iter) {
+  for (size_t iter = 0; iter < n_iter; iter++) {
+    break_optimization(0);
+    // hand unroll the loop to stress the reg alloc.
+    for (size_t i = 0; i <= n_elements - 16; i += 16) {
+      x[i + 0] = i;
+      x[i + 1] = i;
+      x[i + 2] = i;
+      x[i + 3] = i;
+      x[i + 4] = i;
+      x[i + 5] = i;
+      x[i + 6] = i;
+      x[i + 7] = i;
+      x[i + 8] = i;
+      x[i + 9] = i;
+      x[i + 10] = i;
+      x[i + 11] = i;
+      x[i + 12] = i;
+      x[i + 13] = i;
+      x[i + 14] = i;
+      x[i + 15] = i;
+    }
+  }
+}
+
+TEST(AddressSanitizer, ManyAccessBenchmark) {
+  size_t kLen = 1024;
+  int *int_array = new int[kLen];
+  ManyAccessFunc(int_array, kLen, 1 << 24);
+  delete [] int_array;
+}
+
+// access 7 char elements in a 7 byte array (i.e. on the border).
+__attribute__((noinline))
+static void BorderAccessFunc(char *x, size_t n_iter) {
+  for (size_t iter = 0; iter < n_iter; iter++) {
+    break_optimization(x);
+    x[0] = 0;
+    x[1] = 0;
+    x[2] = 0;
+    x[3] = 0;
+    x[4] = 0;
+    x[5] = 0;
+    x[6] = 0;
+  }
+}
+
+TEST(AddressSanitizer, BorderAccessBenchmark) {
+  char *char_7_array = new char[7];
+  BorderAccessFunc(char_7_array, 1 << 30);
+  delete [] char_7_array;
+}
+
+
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_break_optimization.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_break_optimization.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_break_optimization.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_break_optimization.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,18 @@
+//===-- asan_break_optimization.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#include "asan_test_utils.h"
+// Have this function in a separate file to avoid inlining.
+// (Yes, we know about cross-file inlining, but let's assume we don't use it).
+extern "C" void break_optimization(void *x) {
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_globals_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_globals_test.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_globals_test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_globals_test.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,24 @@
+//===-- asan_globals_test.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Some globals in a separate file.
+//===----------------------------------------------------------------------===//
+
+extern char glob5[5];
+static char static10[10];
+
+int GlobalsTest(int zero) {
+  static char func_static15[15];
+  glob5[zero] = 0;
+  static10[zero] = 0;
+  func_static15[zero] = 0;
+  return glob5[1] + func_static15[2];
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_interface_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_interface_test.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_interface_test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_interface_test.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,355 @@
+//===-- asan_interface_test.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <pthread.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "asan_test_config.h"
+#include "asan_test_utils.h"
+#include "asan_interface.h"
+
+TEST(AddressSanitizerInterface, GetEstimatedAllocatedSize) {
+  EXPECT_EQ(1, __asan_get_estimated_allocated_size(0));
+  const size_t sizes[] = { 1, 30, 1<<30 };
+  for (size_t i = 0; i < 3; i++) {
+    EXPECT_EQ(sizes[i], __asan_get_estimated_allocated_size(sizes[i]));
+  }
+}
+
+static const char* kGetAllocatedSizeErrorMsg =
+  "__asan_get_allocated_size failed";
+
+TEST(AddressSanitizerInterface, GetAllocatedSizeAndOwnershipTest) {
+  const size_t kArraySize = 100;
+  char *array = Ident((char*)malloc(kArraySize));
+  int *int_ptr = Ident(new int);
+
+  // Allocated memory is owned by allocator. Allocated size should be
+  // equal to requested size.
+  EXPECT_EQ(true, __asan_get_ownership(array));
+  EXPECT_EQ(kArraySize, __asan_get_allocated_size(array));
+  EXPECT_EQ(true, __asan_get_ownership(int_ptr));
+  EXPECT_EQ(sizeof(int), __asan_get_allocated_size(int_ptr));
+
+  // We cannot call GetAllocatedSize from the memory we didn't map,
+  // and from the interior pointers (not returned by previous malloc).
+  void *wild_addr = (void*)0x1;
+  EXPECT_EQ(false, __asan_get_ownership(wild_addr));
+  EXPECT_DEATH(__asan_get_allocated_size(wild_addr), kGetAllocatedSizeErrorMsg);
+  EXPECT_EQ(false, __asan_get_ownership(array + kArraySize / 2));
+  EXPECT_DEATH(__asan_get_allocated_size(array + kArraySize / 2),
+               kGetAllocatedSizeErrorMsg);
+
+  // NULL is a valid argument and is owned.
+  EXPECT_EQ(true, __asan_get_ownership(NULL));
+  EXPECT_EQ(0, __asan_get_allocated_size(NULL));
+
+  // When memory is freed, it's not owned, and call to GetAllocatedSize
+  // is forbidden.
+  free(array);
+  EXPECT_EQ(false, __asan_get_ownership(array));
+  EXPECT_DEATH(__asan_get_allocated_size(array), kGetAllocatedSizeErrorMsg);
+
+  delete int_ptr;
+}
+
+TEST(AddressSanitizerInterface, EnableStatisticsTest) {
+  bool old_stats_value = __asan_enable_statistics(true);
+  EXPECT_EQ(true, __asan_enable_statistics(false));
+  EXPECT_EQ(false, __asan_enable_statistics(old_stats_value));
+}
+
+TEST(AddressSanitizerInterface, GetCurrentAllocatedBytesTest) {
+  size_t before_malloc, after_malloc, after_free;
+  char *array;
+  const size_t kMallocSize = 100;
+  bool old_stats_value = __asan_enable_statistics(true);
+  before_malloc = __asan_get_current_allocated_bytes();
+
+  array = Ident((char*)malloc(kMallocSize));
+  after_malloc = __asan_get_current_allocated_bytes();
+  EXPECT_EQ(before_malloc + kMallocSize, after_malloc);
+
+  free(array);
+  after_free = __asan_get_current_allocated_bytes();
+  EXPECT_EQ(before_malloc, after_free);
+
+  __asan_enable_statistics(false);
+  array = Ident((char*)malloc(kMallocSize));
+  after_malloc = __asan_get_current_allocated_bytes();
+  EXPECT_EQ(before_malloc, after_malloc);
+
+  free(array);
+  __asan_enable_statistics(old_stats_value);
+}
+
+static void DoDoubleFree() {
+  int *x = Ident(new int);
+  delete Ident(x);
+  delete Ident(x);
+}
+
+// This test is run in a separate process, so that large malloced
+// chunk won't remain in the free lists after the test.
+// Note: use ASSERT_* instead of EXPECT_* here.
+static void RunGetHeapSizeTestAndDie() {
+  size_t old_heap_size, new_heap_size, heap_growth;
+  // We unlikely have have chunk of this size in free list.
+  static const size_t kLargeMallocSize = 1 << 29;  // 512M
+  __asan_enable_statistics(true);
+  old_heap_size = __asan_get_heap_size();
+  fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
+  free(Ident(malloc(kLargeMallocSize)));
+  new_heap_size = __asan_get_heap_size();
+  heap_growth = new_heap_size - old_heap_size;
+  fprintf(stderr, "heap growth after first malloc: %zu\n", heap_growth);
+  ASSERT_GE(heap_growth, kLargeMallocSize);
+  ASSERT_LE(heap_growth, 2 * kLargeMallocSize);
+
+  // Now large chunk should fall into free list, and can be
+  // allocated without increasing heap size.
+  old_heap_size = new_heap_size;
+  free(Ident(malloc(kLargeMallocSize)));
+  heap_growth = __asan_get_heap_size() - old_heap_size;
+  fprintf(stderr, "heap growth after second malloc: %zu\n", heap_growth);
+  ASSERT_LT(heap_growth, kLargeMallocSize);
+
+  // Test passed. Now die with expected double-free.
+  DoDoubleFree();
+}
+
+TEST(AddressSanitizerInterface, GetHeapSizeTest) {
+  EXPECT_DEATH(RunGetHeapSizeTestAndDie(), "double-free");
+}
+
+// Note: use ASSERT_* instead of EXPECT_* here.
+static void DoLargeMallocForGetFreeBytesTestAndDie() {
+  size_t old_free_bytes, new_free_bytes;
+  static const size_t kLargeMallocSize = 1 << 29;  // 512M
+  __asan_enable_statistics(true);
+  // If we malloc and free a large memory chunk, it will not fall
+  // into quarantine and will be available for future requests.
+  old_free_bytes = __asan_get_free_bytes();
+  fprintf(stderr, "allocating %zu bytes:\n", kLargeMallocSize);
+  fprintf(stderr, "free bytes before malloc: %zu\n", old_free_bytes);
+  free(Ident(malloc(kLargeMallocSize)));
+  new_free_bytes = __asan_get_free_bytes();
+  fprintf(stderr, "free bytes after malloc and free: %zu\n", new_free_bytes);
+  ASSERT_GE(new_free_bytes, old_free_bytes + kLargeMallocSize);
+  // Test passed.
+  DoDoubleFree();
+}
+
+TEST(AddressSanitizerInterface, GetFreeBytesTest) {
+  static const size_t kNumOfChunks = 100;
+  static const size_t kChunkSize = 100;
+  char *chunks[kNumOfChunks];
+  size_t i;
+  size_t old_free_bytes, new_free_bytes;
+  bool old_stats_value = __asan_enable_statistics(true);
+  // Allocate a small chunk. Now allocator probably has a lot of these
+  // chunks to fulfill future requests. So, future requests will decrease
+  // the number of free bytes.
+  chunks[0] = Ident((char*)malloc(kChunkSize));
+  old_free_bytes = __asan_get_free_bytes();
+  for (i = 1; i < kNumOfChunks; i++) {
+    chunks[i] = Ident((char*)malloc(kChunkSize));
+    new_free_bytes = __asan_get_free_bytes();
+    EXPECT_LT(new_free_bytes, old_free_bytes);
+    old_free_bytes = new_free_bytes;
+  }
+  // Deleting these chunks will move them to quarantine, number of free
+  // bytes won't increase.
+  for (i = 0; i < kNumOfChunks; i++) {
+    free(chunks[i]);
+    EXPECT_EQ(old_free_bytes, __asan_get_free_bytes());
+  }
+  EXPECT_DEATH(DoLargeMallocForGetFreeBytesTestAndDie(), "double-free");
+  __asan_enable_statistics(old_stats_value);
+}
+
+static const size_t kManyThreadsMallocSizes[] = {5, 1UL<<10, 1UL<<20, 357};
+static const size_t kManyThreadsIterations = 250;
+static const size_t kManyThreadsNumThreads = 200;
+
+void *ManyThreadsWithStatsWorker(void *arg) {
+  for (size_t iter = 0; iter < kManyThreadsIterations; iter++) {
+    for (size_t size_index = 0; size_index < 4; size_index++) {
+      free(Ident(malloc(kManyThreadsMallocSizes[size_index])));
+    }
+  }
+  return 0;
+}
+
+TEST(AddressSanitizerInterface, ManyThreadsWithStatsStressTest) {
+  size_t before_test, after_test, i;
+  pthread_t threads[kManyThreadsNumThreads];
+  bool old_stats_value = __asan_enable_statistics(true);
+  before_test = __asan_get_current_allocated_bytes();
+  for (i = 0; i < kManyThreadsNumThreads; i++) {
+    pthread_create(&threads[i], 0,
+                   (void* (*)(void *x))ManyThreadsWithStatsWorker, (void*)i);
+  }
+  for (i = 0; i < kManyThreadsNumThreads; i++) {
+    pthread_join(threads[i], 0);
+  }
+  after_test = __asan_get_current_allocated_bytes();
+  // ASan stats also reflect memory usage of internal ASan RTL structs,
+  // so we can't check for equality here.
+  EXPECT_LT(after_test, before_test + (1UL<<20));
+  __asan_enable_statistics(old_stats_value);
+}
+
+TEST(AddressSanitizerInterface, ExitCode) {
+  int original_exit_code = __asan_set_error_exit_code(7);
+  EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(7), "");
+  EXPECT_EQ(7, __asan_set_error_exit_code(8));
+  EXPECT_EXIT(DoDoubleFree(), ::testing::ExitedWithCode(8), "");
+  EXPECT_EQ(8, __asan_set_error_exit_code(original_exit_code));
+  EXPECT_EXIT(DoDoubleFree(),
+              ::testing::ExitedWithCode(original_exit_code), "");
+}
+
+static const char* kUseAfterPoisonErrorMessage = "use-after-poison";
+
+#define ACCESS(ptr, offset) Ident(*(ptr + offset))
+
+#define DIE_ON_ACCESS(ptr, offset) \
+    EXPECT_DEATH(Ident(*(ptr + offset)), kUseAfterPoisonErrorMessage)
+
+TEST(AddressSanitizerInterface, SimplePoisonMemoryRegionTest) {
+  char *array = Ident((char*)malloc(120));
+  // poison array[40..80)
+  ASAN_POISON_MEMORY_REGION(array + 40, 40);
+  ACCESS(array, 39);
+  ACCESS(array, 80);
+  DIE_ON_ACCESS(array, 40);
+  DIE_ON_ACCESS(array, 60);
+  DIE_ON_ACCESS(array, 79);
+  ASAN_UNPOISON_MEMORY_REGION(array + 40, 40);
+  // access previously poisoned memory.
+  ACCESS(array, 40);
+  ACCESS(array, 79);
+  free(array);
+}
+
+TEST(AddressSanitizerInterface, OverlappingPoisonMemoryRegionTest) {
+  char *array = Ident((char*)malloc(120));
+  // Poison [0..40) and [80..120)
+  ASAN_POISON_MEMORY_REGION(array, 40);
+  ASAN_POISON_MEMORY_REGION(array + 80, 40);
+  DIE_ON_ACCESS(array, 20);
+  ACCESS(array, 60);
+  DIE_ON_ACCESS(array, 100);
+  // Poison whole array - [0..120)
+  ASAN_POISON_MEMORY_REGION(array, 120);
+  DIE_ON_ACCESS(array, 60);
+  // Unpoison [24..96)
+  ASAN_UNPOISON_MEMORY_REGION(array + 24, 72);
+  DIE_ON_ACCESS(array, 23);
+  ACCESS(array, 24);
+  ACCESS(array, 60);
+  ACCESS(array, 95);
+  DIE_ON_ACCESS(array, 96);
+  free(array);
+}
+
+TEST(AddressSanitizerInterface, PushAndPopWithPoisoningTest) {
+  // Vector of capacity 20
+  char *vec = Ident((char*)malloc(20));
+  ASAN_POISON_MEMORY_REGION(vec, 20);
+  for (size_t i = 0; i < 7; i++) {
+    // Simulate push_back.
+    ASAN_UNPOISON_MEMORY_REGION(vec + i, 1);
+    ACCESS(vec, i);
+    DIE_ON_ACCESS(vec, i + 1);
+  }
+  for (size_t i = 7; i > 0; i--) {
+    // Simulate pop_back.
+    ASAN_POISON_MEMORY_REGION(vec + i - 1, 1);
+    DIE_ON_ACCESS(vec, i - 1);
+    if (i > 1) ACCESS(vec, i - 2);
+  }
+  free(vec);
+}
+
+// Make sure that each aligned block of size "2^granularity" doesn't have
+// "true" value before "false" value.
+static void MakeShadowValid(bool *shadow, int length, int granularity) {
+  bool can_be_poisoned = true;
+  for (int i = length - 1; i >= 0; i--) {
+    can_be_poisoned &= shadow[i];
+    shadow[i] &= can_be_poisoned;
+    if (i % (1 << granularity) == 0) {
+      can_be_poisoned = true;
+    }
+  }
+}
+
+TEST(AddressSanitizerInterface, PoisoningStressTest) {
+  const size_t kSize = 24;
+  bool expected[kSize];
+  char *arr = Ident((char*)malloc(kSize));
+  for (size_t l1 = 0; l1 < kSize; l1++) {
+    for (size_t s1 = 1; l1 + s1 <= kSize; s1++) {
+      for (size_t l2 = 0; l2 < kSize; l2++) {
+        for (size_t s2 = 1; l2 + s2 <= kSize; s2++) {
+          // Poison [l1, l1+s1), [l2, l2+s2) and check result.
+          ASAN_UNPOISON_MEMORY_REGION(arr, kSize);
+          ASAN_POISON_MEMORY_REGION(arr + l1, s1);
+          ASAN_POISON_MEMORY_REGION(arr + l2, s2);
+          memset(expected, false, kSize);
+          memset(expected + l1, true, s1);
+          MakeShadowValid(expected, 24, /*granularity*/ 3);
+          memset(expected + l2, true, s2);
+          MakeShadowValid(expected, 24, /*granularity*/ 3);
+          for (size_t i = 0; i < kSize; i++) {
+            ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+          }
+          // Unpoison [l1, l1+s1) and [l2, l2+s2) and check result.
+          ASAN_POISON_MEMORY_REGION(arr, kSize);
+          ASAN_UNPOISON_MEMORY_REGION(arr + l1, s1);
+          ASAN_UNPOISON_MEMORY_REGION(arr + l2, s2);
+          memset(expected, true, kSize);
+          memset(expected + l1, false, s1);
+          MakeShadowValid(expected, 24, /*granularity*/ 3);
+          memset(expected + l2, false, s2);
+          MakeShadowValid(expected, 24, /*granularity*/ 3);
+          for (size_t i = 0; i < kSize; i++) {
+            ASSERT_EQ(expected[i], __asan_address_is_poisoned(arr + i));
+          }
+        }
+      }
+    }
+  }
+}
+
+static const char *kInvalidPoisonMessage = "invalid-poison-memory-range";
+static const char *kInvalidUnpoisonMessage = "invalid-unpoison-memory-range";
+
+TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
+  char *array = Ident((char*)malloc(120));
+  ASAN_UNPOISON_MEMORY_REGION(array, 120);
+  // Try to unpoison not owned memory
+  EXPECT_DEATH(ASAN_UNPOISON_MEMORY_REGION(array, 121),
+               kInvalidUnpoisonMessage);
+  EXPECT_DEATH(ASAN_UNPOISON_MEMORY_REGION(array - 1, 120),
+               kInvalidUnpoisonMessage);
+
+  ASAN_POISON_MEMORY_REGION(array, 120);
+  // Try to poison not owned memory.
+  EXPECT_DEATH(ASAN_POISON_MEMORY_REGION(array, 121), kInvalidPoisonMessage);
+  EXPECT_DEATH(ASAN_POISON_MEMORY_REGION(array - 1, 120),
+               kInvalidPoisonMessage);
+  free(array);
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_mac_test.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_mac_test.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_mac_test.h (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_mac_test.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,16 @@
+extern "C" {
+  void CFAllocatorDefaultDoubleFree();
+  void CFAllocatorSystemDefaultDoubleFree();
+  void CFAllocatorMallocDoubleFree();
+  void CFAllocatorMallocZoneDoubleFree();
+  void CallFreeOnWorkqueue(void *mem);
+  void TestGCDDispatchAsync();
+  void TestGCDDispatchSync();
+  void TestGCDReuseWqthreadsAsync();
+  void TestGCDReuseWqthreadsSync();
+  void TestGCDDispatchAfter();
+  void TestGCDInTSDDestructor();
+  void TestGCDSourceEvent();
+  void TestGCDSourceCancel();
+  void TestGCDGroupAsync();
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_mac_test.mm
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_mac_test.mm?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_mac_test.mm (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_mac_test.mm Tue Nov 29 19:07:02 2011
@@ -0,0 +1,203 @@
+// Mac OS X 10.6 or higher only.
+#include <dispatch/dispatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#import <CoreFoundation/CFBase.h>
+#import <Foundation/NSObject.h>
+
+void CFAllocatorDefaultDoubleFree() {
+  void *mem =  CFAllocatorAllocate(kCFAllocatorDefault, 5, 0);
+  CFAllocatorDeallocate(kCFAllocatorDefault, mem);
+  CFAllocatorDeallocate(kCFAllocatorDefault, mem);
+}
+
+void CFAllocatorSystemDefaultDoubleFree() {
+  void *mem =  CFAllocatorAllocate(kCFAllocatorSystemDefault, 5, 0);
+  CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
+  CFAllocatorDeallocate(kCFAllocatorSystemDefault, mem);
+}
+
+void CFAllocatorMallocDoubleFree() {
+  void *mem =  CFAllocatorAllocate(kCFAllocatorMalloc, 5, 0);
+  CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
+  CFAllocatorDeallocate(kCFAllocatorMalloc, mem);
+}
+
+void CFAllocatorMallocZoneDoubleFree() {
+  void *mem =  CFAllocatorAllocate(kCFAllocatorMallocZone, 5, 0);
+  CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
+  CFAllocatorDeallocate(kCFAllocatorMallocZone, mem);
+}
+
+
+// Test the +load instrumentation.
+// Because the +load methods are invoked before anything else is initialized,
+// it makes little sense to wrap the code below into a gTest test case.
+// If AddressSanitizer doesn't instrument the +load method below correctly,
+// everything will just crash.
+
+char kStartupStr[] =
+    "If your test didn't crash, AddressSanitizer is instrumenting "
+    "the +load methods correctly.";
+
+ at interface LoadSomething : NSObject {
+}
+ at end
+
+ at implementation LoadSomething
+
++(void) load {
+  for (int i = 0; i < strlen(kStartupStr); i++) {
+    volatile char ch = kStartupStr[i];  // make sure no optimizations occur.
+  }
+  // Don't print anything here not to interfere with the death tests.
+}
+
+ at end
+
+void worker_do_alloc(int size) {
+  char *mem = malloc(size);
+  mem[0] = 0; // Ok
+  free(mem);
+}
+
+void worker_do_crash(int size) {
+  char *mem = malloc(size);
+  mem[size] = 0;  // BOOM
+  free(mem);
+}
+
+// Tests for the Grand Central Dispatch. See
+// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// for the reference.
+
+void TestGCDDispatchAsync() {
+  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+  dispatch_block_t block = ^{ worker_do_crash(1024); };
+  // dispatch_async() runs the task on a worker thread that does not go through
+  // pthread_create(). We need to verify that AddressSanitizer notices that the
+  // thread has started.
+  dispatch_async(queue, block);
+  // TODO(glider): this is hacky. Need to wait for the worker instead.
+  sleep(1);
+}
+
+void TestGCDDispatchSync() {
+  dispatch_queue_t queue = dispatch_get_global_queue(2, 0);
+  dispatch_block_t block = ^{ worker_do_crash(1024); };
+  // dispatch_sync() runs the task on a worker thread that does not go through
+  // pthread_create(). We need to verify that AddressSanitizer notices that the
+  // thread has started.
+  dispatch_sync(queue, block);
+  // TODO(glider): this is hacky. Need to wait for the worker instead.
+  sleep(1);
+}
+
+// libdispatch spawns a rather small number of threads and reuses them. We need
+// to make sure AddressSanitizer handles the reusing correctly.
+void TestGCDReuseWqthreadsAsync() {
+  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+  dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
+  dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+  for (int i = 0; i < 100; i++) {
+    dispatch_async(queue, block_alloc);
+  }
+  dispatch_async(queue, block_crash);
+  // TODO(glider): this is hacky. Need to wait for the workers instead.
+  sleep(1);
+}
+
+// Try to trigger abnormal behaviour of dispatch_sync() being unhandled by us.
+void TestGCDReuseWqthreadsSync() {
+  dispatch_queue_t queue[4];
+  queue[0] = dispatch_get_global_queue(2, 0);
+  queue[1] = dispatch_get_global_queue(0, 0);
+  queue[2] = dispatch_get_global_queue(-2, 0);
+  queue[3] = dispatch_queue_create("my_queue", NULL);
+  dispatch_block_t block_alloc = ^{ worker_do_alloc(1024); };
+  dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+  for (int i = 0; i < 1000; i++) {
+    dispatch_sync(queue[i % 4], block_alloc);
+  }
+  dispatch_sync(queue[3], block_crash);
+  // TODO(glider): this is hacky. Need to wait for the workers instead.
+  sleep(1);
+}
+
+void TestGCDDispatchAfter() {
+  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+  dispatch_block_t block_crash = ^{ worker_do_crash(1024); };
+  // Schedule the event one second from the current time.
+  dispatch_time_t milestone =
+      dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+  dispatch_after(milestone, queue, block_crash);
+  // Let's wait for a bit longer now.
+  // TODO(glider): this is still hacky.
+  sleep(2);
+}
+
+void worker_do_deallocate(void *ptr) {
+  free(ptr);
+}
+
+void CallFreeOnWorkqueue(void *tsd) {
+  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+  dispatch_block_t block_dealloc = ^{ worker_do_deallocate(tsd); };
+  dispatch_async(queue, block_dealloc);
+  // Do not wait for the worker to free the memory -- nobody is going to touch
+  // it.
+}
+
+void TestGCDSourceEvent() {
+  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+  dispatch_source_t timer =
+      dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+  // Schedule the timer one second from the current time.
+  dispatch_time_t milestone =
+      dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+
+  dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
+  char *mem = malloc(10);
+  dispatch_source_set_event_handler(timer, ^{
+    mem[10] = 1;
+  });
+  dispatch_resume(timer);
+  sleep(2);
+}
+
+void TestGCDSourceCancel() {
+  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+  dispatch_source_t timer =
+      dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
+  // Schedule the timer one second from the current time.
+  dispatch_time_t milestone =
+      dispatch_time(DISPATCH_TIME_NOW, 1LL * NSEC_PER_SEC);
+
+  dispatch_source_set_timer(timer, milestone, DISPATCH_TIME_FOREVER, 0);
+  char *mem = malloc(10);
+  // Both dispatch_source_set_cancel_handler() and
+  // dispatch_source_set_event_handler() use dispatch_barrier_async_f().
+  // It's tricky to test dispatch_source_set_cancel_handler() separately,
+  // so we test both here.
+  dispatch_source_set_event_handler(timer, ^{
+    dispatch_source_cancel(timer);
+  });
+  dispatch_source_set_cancel_handler(timer, ^{
+    mem[10] = 1;
+  });
+  dispatch_resume(timer);
+  sleep(2);
+}
+
+void TestGCDGroupAsync() {
+  dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
+  dispatch_group_t group = dispatch_group_create(); 
+  char *mem = malloc(10);
+  dispatch_group_async(group, queue, ^{
+    mem[10] = 1;
+  });
+  dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_noinst_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_noinst_test.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_noinst_test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_noinst_test.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,331 @@
+//===-- asan_noinst_test.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This test file should be compiled w/o asan instrumentation.
+//===----------------------------------------------------------------------===//
+#include "asan_allocator.h"
+#include "asan_interface.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "asan_stack.h"
+#include "asan_test_utils.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vector>
+#include <algorithm>
+#include "gtest/gtest.h"
+
+// Simple stand-alone pseudorandom number generator.
+// Current algorithm is ANSI C linear congruential PRNG.
+static inline uint32_t my_rand(uint32_t* state) {
+  return (*state = *state * 1103515245 + 12345) >> 16;
+}
+
+static uint32_t global_seed = 0;
+
+
+TEST(AddressSanitizer, InternalSimpleDeathTest) {
+  EXPECT_DEATH(exit(1), "");
+}
+
+static void MallocStress(size_t n) {
+  uint32_t seed = my_rand(&global_seed);
+  __asan::AsanStackTrace stack1;
+  stack1.trace[0] = 0xa123;
+  stack1.trace[1] = 0xa456;
+  stack1.size = 2;
+
+  __asan::AsanStackTrace stack2;
+  stack2.trace[0] = 0xb123;
+  stack2.trace[1] = 0xb456;
+  stack2.size = 2;
+
+  __asan::AsanStackTrace stack3;
+  stack3.trace[0] = 0xc123;
+  stack3.trace[1] = 0xc456;
+  stack3.size = 2;
+
+  std::vector<void *> vec;
+  for (size_t i = 0; i < n; i++) {
+    if ((i % 3) == 0) {
+      if (vec.empty()) continue;
+      size_t idx = my_rand(&seed) % vec.size();
+      void *ptr = vec[idx];
+      vec[idx] = vec.back();
+      vec.pop_back();
+      __asan::asan_free(ptr, &stack1);
+    } else {
+      size_t size = my_rand(&seed) % 1000 + 1;
+      switch ((my_rand(&seed) % 128)) {
+        case 0: size += 1024; break;
+        case 1: size += 2048; break;
+        case 2: size += 4096; break;
+      }
+      size_t alignment = 1 << (my_rand(&seed) % 10 + 1);
+      char *ptr = (char*)__asan::asan_memalign(alignment, size, &stack2);
+      vec.push_back(ptr);
+      ptr[0] = 0;
+      ptr[size-1] = 0;
+      ptr[size/2] = 0;
+    }
+  }
+  for (size_t i = 0; i < vec.size(); i++)
+    __asan::asan_free(vec[i], &stack3);
+}
+
+
+TEST(AddressSanitizer, NoInstMallocTest) {
+#ifdef __arm__
+  MallocStress(300000);
+#else
+  MallocStress(1000000);
+#endif
+}
+
+static void PrintShadow(const char *tag, uintptr_t ptr, size_t size) {
+  fprintf(stderr, "%s shadow: %lx size % 3ld: ", tag, (long)ptr, (long)size);
+  uintptr_t prev_shadow = 0;
+  for (intptr_t i = -32; i < (intptr_t)size + 32; i++) {
+    uintptr_t shadow = __asan::MemToShadow(ptr + i);
+    if (i == 0 || i == (intptr_t)size)
+      fprintf(stderr, ".");
+    if (shadow != prev_shadow) {
+      prev_shadow = shadow;
+      fprintf(stderr, "%02x", (int)*(uint8_t*)shadow);
+    }
+  }
+  fprintf(stderr, "\n");
+}
+
+TEST(AddressSanitizer, DISABLED_InternalPrintShadow) {
+  for (size_t size = 1; size <= 513; size++) {
+    char *ptr = new char[size];
+    PrintShadow("m", (uintptr_t)ptr, size);
+    delete [] ptr;
+    PrintShadow("f", (uintptr_t)ptr, size);
+  }
+}
+
+static uintptr_t pc_array[] = {
+#if __WORDSIZE == 64
+  0x7effbf756068ULL,
+  0x7effbf75e5abULL,
+  0x7effc0625b7cULL,
+  0x7effc05b8997ULL,
+  0x7effbf990577ULL,
+  0x7effbf990c56ULL,
+  0x7effbf992f3cULL,
+  0x7effbf950c22ULL,
+  0x7effc036dba0ULL,
+  0x7effc03638a3ULL,
+  0x7effc035be4aULL,
+  0x7effc0539c45ULL,
+  0x7effc0539a65ULL,
+  0x7effc03db9b3ULL,
+  0x7effc03db100ULL,
+  0x7effc037c7b8ULL,
+  0x7effc037bfffULL,
+  0x7effc038b777ULL,
+  0x7effc038021cULL,
+  0x7effc037c7d1ULL,
+  0x7effc037bfffULL,
+  0x7effc038b777ULL,
+  0x7effc038021cULL,
+  0x7effc037c7d1ULL,
+  0x7effc037bfffULL,
+  0x7effc038b777ULL,
+  0x7effc038021cULL,
+  0x7effc037c7d1ULL,
+  0x7effc037bfffULL,
+  0x7effc0520d26ULL,
+  0x7effc009ddffULL,
+  0x7effbf90bb50ULL,
+  0x7effbdddfa69ULL,
+  0x7effbdde1fe2ULL,
+  0x7effbdde2424ULL,
+  0x7effbdde27b3ULL,
+  0x7effbddee53bULL,
+  0x7effbdde1988ULL,
+  0x7effbdde0904ULL,
+  0x7effc106ce0dULL,
+  0x7effbcc3fa04ULL,
+  0x7effbcc3f6a4ULL,
+  0x7effbcc3e726ULL,
+  0x7effbcc40852ULL,
+  0x7effb681ec4dULL,
+#endif  // __WORDSIZE
+  0xB0B5E768,
+  0x7B682EC1,
+  0x367F9918,
+  0xAE34E13,
+  0xBA0C6C6,
+  0x13250F46,
+  0xA0D6A8AB,
+  0x2B07C1A8,
+  0x6C844F4A,
+  0x2321B53,
+  0x1F3D4F8F,
+  0x3FE2924B,
+  0xB7A2F568,
+  0xBD23950A,
+  0x61020930,
+  0x33E7970C,
+  0x405998A1,
+  0x59F3551D,
+  0x350E3028,
+  0xBC55A28D,
+  0x361F3AED,
+  0xBEAD0F73,
+  0xAEF28479,
+  0x757E971F,
+  0xAEBA450,
+  0x43AD22F5,
+  0x8C2C50C4,
+  0x7AD8A2E1,
+  0x69EE4EE8,
+  0xC08DFF,
+  0x4BA6538,
+  0x3708AB2,
+  0xC24B6475,
+  0x7C8890D7,
+  0x6662495F,
+  0x9B641689,
+  0xD3596B,
+  0xA1049569,
+  0x44CBC16,
+  0x4D39C39F
+};
+
+void CompressStackTraceTest(size_t n_iter) {
+  uint32_t seed = my_rand(&global_seed);
+  const size_t kNumPcs = ASAN_ARRAY_SIZE(pc_array);
+  uint32_t compressed[2 * kNumPcs];
+
+  for (size_t iter = 0; iter < n_iter; iter++) {
+    std::random_shuffle(pc_array, pc_array + kNumPcs);
+    __asan::AsanStackTrace stack0, stack1;
+    stack0.CopyFrom(pc_array, kNumPcs);
+    stack0.size = std::max((size_t)1, (size_t)my_rand(&seed) % stack0.size);
+    size_t compress_size =
+      std::max((size_t)2, (size_t)my_rand(&seed) % (2 * kNumPcs));
+    size_t n_frames =
+      __asan::AsanStackTrace::CompressStack(&stack0, compressed, compress_size);
+    assert(n_frames <= stack0.size);
+    __asan::AsanStackTrace::UncompressStack(&stack1, compressed, compress_size);
+    assert(stack1.size == n_frames);
+    for (size_t i = 0; i < stack1.size; i++) {
+      assert(stack0.trace[i] == stack1.trace[i]);
+    }
+  }
+}
+
+TEST(AddressSanitizer, CompressStackTraceTest) {
+  CompressStackTraceTest(10000);
+}
+
+void CompressStackTraceBenchmark(size_t n_iter) {
+  const size_t kNumPcs = ASAN_ARRAY_SIZE(pc_array);
+  uint32_t compressed[2 * kNumPcs];
+  std::random_shuffle(pc_array, pc_array + kNumPcs);
+
+  __asan::AsanStackTrace stack0;
+  stack0.CopyFrom(pc_array, kNumPcs);
+  stack0.size = kNumPcs;
+  for (size_t iter = 0; iter < n_iter; iter++) {
+    size_t compress_size = kNumPcs;
+    size_t n_frames =
+      __asan::AsanStackTrace::CompressStack(&stack0, compressed, compress_size);
+    Ident(n_frames);
+  }
+}
+
+TEST(AddressSanitizer, CompressStackTraceBenchmark) {
+  CompressStackTraceBenchmark(1 << 24);
+}
+
+TEST(AddressSanitizer, QuarantineTest) {
+  __asan::AsanStackTrace stack;
+  stack.trace[0] = 0x890;
+  stack.size = 1;
+
+  const int size = 32;
+  void *p = __asan::asan_malloc(size, &stack);
+  __asan::asan_free(p, &stack);
+  size_t i;
+  size_t max_i = 1 << 30;
+  for (i = 0; i < max_i; i++) {
+    void *p1 = __asan::asan_malloc(size, &stack);
+    __asan::asan_free(p1, &stack);
+    if (p1 == p) break;
+  }
+  // fprintf(stderr, "i=%ld\n", i);
+  EXPECT_GE(i, 100000U);
+  EXPECT_LT(i, max_i);
+}
+
+void *ThreadedQuarantineTestWorker(void *unused) {
+  uint32_t seed = my_rand(&global_seed);
+  __asan::AsanStackTrace stack;
+  stack.trace[0] = 0x890;
+  stack.size = 1;
+
+  for (size_t i = 0; i < 1000; i++) {
+    void *p = __asan::asan_malloc(1 + (my_rand(&seed) % 4000), &stack);
+    __asan::asan_free(p, &stack);
+  }
+  return NULL;
+}
+
+// Check that the thread local allocators are flushed when threads are
+// destroyed.
+TEST(AddressSanitizer, ThreadedQuarantineTest) {
+  const int n_threads = 3000;
+  bool old_flag_stats = __asan_enable_statistics(true);
+  size_t mmaped1 = __asan_get_heap_size();
+  for (int i = 0; i < n_threads; i++) {
+    pthread_t t;
+    pthread_create(&t, NULL, ThreadedQuarantineTestWorker, 0);
+    pthread_join(t, 0);
+    size_t mmaped2 = __asan_get_heap_size();
+    EXPECT_LT(mmaped2 - mmaped1, 320U * (1 << 20));
+  }
+  __asan_enable_statistics(old_flag_stats);
+}
+
+void *ThreadedOneSizeMallocStress(void *unused) {
+  __asan::AsanStackTrace stack;
+  stack.trace[0] = 0x890;
+  stack.size = 1;
+  const size_t kNumMallocs = 1000;
+  for (int iter = 0; iter < 1000; iter++) {
+    void *p[kNumMallocs];
+    for (size_t i = 0; i < kNumMallocs; i++) {
+      p[i] = __asan::asan_malloc(32, &stack);
+    }
+    for (size_t i = 0; i < kNumMallocs; i++) {
+      __asan::asan_free(p[i], &stack);
+    }
+  }
+  return NULL;
+}
+
+TEST(AddressSanitizer, ThreadedOneSizeMallocStressTest) {
+  const int kNumThreads = 4;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, ThreadedOneSizeMallocStress, 0);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_test.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_test.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,1896 @@
+//===-- asan_test.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <assert.h>
+
+#if defined(__i386__) or defined(__x86_64__)
+#include <emmintrin.h>
+#endif
+
+#include "asan_test_config.h"
+#include "asan_test_utils.h"
+
+#ifndef __APPLE__
+#include <malloc.h>
+#endif  // __APPLE__
+
+#ifdef __APPLE__
+static bool APPLE = true;
+#else
+static bool APPLE = false;
+#endif
+
+#if ASAN_HAS_EXCEPTIONS
+# define ASAN_THROW(x) throw (x)
+#else
+# define ASAN_THROW(x)
+#endif
+
+#include <sys/mman.h>
+
+typedef uint8_t   U1;
+typedef uint16_t  U2;
+typedef uint32_t  U4;
+typedef uint64_t  U8;
+
+static const char *progname;
+static const int kPageSize = 4096;
+
+// Simple stand-alone pseudorandom number generator.
+// Current algorithm is ANSI C linear congruential PRNG.
+static inline uint32_t my_rand(uint32_t* state) {
+  return (*state = *state * 1103515245 + 12345) >> 16;
+}
+
+static uint32_t global_seed = 0;
+
+class ObjdumpOfMyself {
+ public:
+  explicit ObjdumpOfMyself(const string &binary) {
+    is_correct = true;
+    string objdump_name = APPLE ? "gobjdump" : "objdump";
+    string prog = objdump_name + " -d " + binary;
+    // TODO(glider): popen() succeeds even if the file does not exist.
+    FILE *pipe = popen(prog.c_str(), "r");
+    string objdump;
+    if (pipe) {
+      const int kBuffSize = 4096;
+      char buff[kBuffSize+1];
+      int read_bytes;
+      while ((read_bytes = fread(buff, 1, kBuffSize, pipe)) > 0) {
+        buff[read_bytes] = 0;
+        objdump.append(buff);
+      }
+      pclose(pipe);
+    } else {
+      is_correct = false;
+    }
+    // cut the objdump into functions
+    string fn, next_fn;
+    size_t next_start;
+    for (size_t start = fn_start(objdump, 0, &fn);
+         start != string::npos;
+         start = next_start, fn = next_fn) {
+      next_start = fn_start(objdump, start, &next_fn);
+      // fprintf(stderr, "start: %d next_start = %d fn: %s\n",
+      //        (int)start, (int)next_start, fn.c_str());
+      // Mac OS adds the "_" prefix to function names.
+      if (fn.find(APPLE ? "_Disasm" : "Disasm") == string::npos) {
+        continue;
+      }
+      string fn_body = objdump.substr(start, next_start - start);
+      // fprintf(stderr, "%s:\n%s", fn.c_str(), fn_body.c_str());
+      functions_[fn] = fn_body;
+    }
+  }
+
+  string &GetFuncDisasm(const string &fn) {
+    return functions_[fn];
+  }
+
+  int CountInsnInFunc(const string &fn, const vector<string> &insns) {
+    // Mac OS adds the "_" prefix to function names.
+    string fn_ref = APPLE ? "_" + fn : fn;
+    const string &disasm = GetFuncDisasm(fn_ref);
+    if (disasm.empty()) return -1;
+    size_t counter = 0;
+    for (size_t i = 0; i < insns.size(); i++) {
+      size_t pos = 0;
+      while ((pos = disasm.find(insns[i], pos)) != string::npos) {
+        counter++;
+        pos++;
+      }
+    }
+    return counter;
+  }
+
+  bool IsCorrect() { return is_correct; }
+
+ private:
+  size_t fn_start(const string &objdump, size_t start_pos, string *fn) {
+    size_t pos = objdump.find(">:\n", start_pos);
+    if (pos == string::npos)
+      return string::npos;
+    size_t beg = pos;
+    while (beg > 0 && objdump[beg - 1] != '<')
+      beg--;
+    *fn = objdump.substr(beg, pos - beg);
+    return pos + 3;
+  }
+
+  map<string, string> functions_;
+  bool is_correct;
+};
+
+static ObjdumpOfMyself *objdump_of_myself() {
+  static ObjdumpOfMyself *o = new ObjdumpOfMyself(progname);
+  return o;
+}
+
+const size_t kLargeMalloc = 1 << 24;
+
+template<class T>
+__attribute__((noinline))
+void asan_write(T *a) {
+  *a = 0;
+}
+
+__attribute__((noinline))
+void asan_write_sized_aligned(uint8_t *p, size_t size) {
+  EXPECT_EQ(0, ((uintptr_t)p % size));
+  if      (size == 1) asan_write((uint8_t*)p);
+  else if (size == 2) asan_write((uint16_t*)p);
+  else if (size == 4) asan_write((uint32_t*)p);
+  else if (size == 8) asan_write((uint64_t*)p);
+}
+
+__attribute__((noinline)) void *malloc_fff(size_t size) {
+  void *res = malloc/**/(size); break_optimization(0); return res;}
+__attribute__((noinline)) void *malloc_eee(size_t size) {
+  void *res = malloc_fff(size); break_optimization(0); return res;}
+__attribute__((noinline)) void *malloc_ddd(size_t size) {
+  void *res = malloc_eee(size); break_optimization(0); return res;}
+__attribute__((noinline)) void *malloc_ccc(size_t size) {
+  void *res = malloc_ddd(size); break_optimization(0); return res;}
+__attribute__((noinline)) void *malloc_bbb(size_t size) {
+  void *res = malloc_ccc(size); break_optimization(0); return res;}
+__attribute__((noinline)) void *malloc_aaa(size_t size) {
+  void *res = malloc_bbb(size); break_optimization(0); return res;}
+
+#ifndef __APPLE__
+__attribute__((noinline)) void *memalign_fff(size_t alignment, size_t size) {
+  void *res = memalign/**/(alignment, size); break_optimization(0); return res;}
+__attribute__((noinline)) void *memalign_eee(size_t alignment, size_t size) {
+  void *res = memalign_fff(alignment, size); break_optimization(0); return res;}
+__attribute__((noinline)) void *memalign_ddd(size_t alignment, size_t size) {
+  void *res = memalign_eee(alignment, size); break_optimization(0); return res;}
+__attribute__((noinline)) void *memalign_ccc(size_t alignment, size_t size) {
+  void *res = memalign_ddd(alignment, size); break_optimization(0); return res;}
+__attribute__((noinline)) void *memalign_bbb(size_t alignment, size_t size) {
+  void *res = memalign_ccc(alignment, size); break_optimization(0); return res;}
+__attribute__((noinline)) void *memalign_aaa(size_t alignment, size_t size) {
+  void *res = memalign_bbb(alignment, size); break_optimization(0); return res;}
+#endif  // __APPLE__
+
+
+__attribute__((noinline))
+  void free_ccc(void *p) { free(p); break_optimization(0);}
+__attribute__((noinline))
+  void free_bbb(void *p) { free_ccc(p); break_optimization(0);}
+__attribute__((noinline))
+  void free_aaa(void *p) { free_bbb(p); break_optimization(0);}
+
+template<class T>
+__attribute__((noinline))
+void oob_test(int size, int off) {
+  char *p = (char*)malloc_aaa(size);
+  // fprintf(stderr, "writing %d byte(s) into [%p,%p) with offset %d\n",
+  //        sizeof(T), p, p + size, off);
+  asan_write((T*)(p + off));
+  free_aaa(p);
+}
+
+
+template<class T>
+__attribute__((noinline))
+void uaf_test(int size, int off) {
+  char *p = (char *)malloc_aaa(size);
+  free_aaa(p);
+  for (int i = 1; i < 100; i++)
+    free_aaa(malloc_aaa(i));
+  fprintf(stderr, "writing %ld byte(s) at %p with offset %d\n",
+          (long)sizeof(T), p, off);
+  asan_write((T*)(p + off));
+}
+
+TEST(AddressSanitizer, ADDRESS_SANITIZER_MacroTest) {
+  EXPECT_EQ(1, ADDRESS_SANITIZER);
+}
+
+TEST(AddressSanitizer, SimpleDeathTest) {
+  EXPECT_DEATH(exit(1), "");
+}
+
+TEST(AddressSanitizer, VariousMallocsTest) {
+  // fprintf(stderr, "malloc:\n");
+  int *a = (int*)malloc(100 * sizeof(int));
+  a[50] = 0;
+  free(a);
+
+  // fprintf(stderr, "realloc:\n");
+  int *r = (int*)malloc(10);
+  r = (int*)realloc(r, 2000 * sizeof(int));
+  r[1000] = 0;
+  free(r);
+
+  // fprintf(stderr, "operator new []\n");
+  int *b = new int[100];
+  b[50] = 0;
+  delete [] b;
+
+  // fprintf(stderr, "operator new\n");
+  int *c = new int;
+  *c = 0;
+  delete c;
+
+#ifndef __APPLE__
+  // cfree
+  cfree(Ident(malloc(1)));
+
+  // fprintf(stderr, "posix_memalign\n");
+  int *pm;
+  int pm_res = posix_memalign((void**)&pm, kPageSize, kPageSize);
+  EXPECT_EQ(0, pm_res);
+  free(pm);
+
+  int *ma = (int*)memalign(kPageSize, kPageSize);
+  EXPECT_EQ(0, (uintptr_t)ma % kPageSize);
+  ma[123] = 0;
+  free(ma);
+#endif  // __APPLE__
+}
+
+TEST(AddressSanitizer, CallocTest) {
+  int *a = (int*)calloc(100, sizeof(int));
+  EXPECT_EQ(0, a[10]);
+  free(a);
+}
+
+TEST(AddressSanitizer, VallocTest) {
+  void *a = valloc(100);
+  EXPECT_EQ(0, (uintptr_t)a % kPageSize);
+  free(a);
+}
+
+#ifndef __APPLE__
+TEST(AddressSanitizer, PvallocTest) {
+  char *a = (char*)pvalloc(kPageSize + 100);
+  EXPECT_EQ(0, (uintptr_t)a % kPageSize);
+  a[kPageSize + 101] = 1;  // we should not report an error here.
+  free(a);
+
+  a = (char*)pvalloc(0);  // pvalloc(0) should allocate at least one page.
+  EXPECT_EQ(0, (uintptr_t)a % kPageSize);
+  a[101] = 1;  // we should not report an error here.
+  free(a);
+}
+#endif  // __APPLE__
+
+void NoOpSignalHandler(int unused) {
+  fprintf(stderr, "NoOpSignalHandler (should not happen). Aborting\n");
+  abort();
+}
+
+void NoOpSigaction(int, siginfo_t *siginfo, void *context) {
+  fprintf(stderr, "NoOpSigaction (should not happen). Aborting\n");
+  abort();
+}
+
+TEST(AddressSanitizer, SignalTest) {
+  signal(SIGSEGV, NoOpSignalHandler);
+  signal(SIGILL, NoOpSignalHandler);
+  // If asan did not intercept sigaction NoOpSigaction will fire.
+  char *x = Ident((char*)malloc(5));
+  EXPECT_DEATH(x[6]++, "is located 1 bytes to the right");
+  free(Ident(x));
+}
+
+TEST(AddressSanitizer, SigactionTest) {
+  {
+    struct sigaction sigact;
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_sigaction = NoOpSigaction;;
+    sigact.sa_flags = SA_SIGINFO;
+    sigaction(SIGSEGV, &sigact, 0);
+  }
+
+  {
+    struct sigaction sigact;
+    memset(&sigact, 0, sizeof(sigact));
+    sigact.sa_sigaction = NoOpSigaction;;
+    sigact.sa_flags = SA_SIGINFO;
+    sigaction(SIGILL, &sigact, 0);
+  }
+
+  // If asan did not intercept sigaction NoOpSigaction will fire.
+  char *x = Ident((char*)malloc(5));
+  EXPECT_DEATH(x[6]++, "is located 1 bytes to the right");
+  free(Ident(x));
+}
+
+void *TSDWorker(void *test_key) {
+  if (test_key) {
+    pthread_setspecific(*(pthread_key_t*)test_key, (void*)0xfeedface);
+  }
+  return NULL;
+}
+
+void TSDDestructor(void *tsd) {
+  // Spawning a thread will check that the current thread id is not -1.
+  pthread_t th;
+  pthread_create(&th, NULL, TSDWorker, NULL);
+  pthread_join(th, NULL);
+}
+
+// This tests triggers the thread-specific data destruction fiasco which occurs
+// if we don't manage the TSD destructors ourselves. We create a new pthread
+// key with a non-NULL destructor which is likely to be put after the destructor
+// of AsanThread in the list of destructors.
+// In this case the TSD for AsanThread will be destroyed before TSDDestructor
+// is called for the child thread, and a CHECK will fail when we call
+// pthread_create() to spawn the grandchild.
+TEST(AddressSanitizer, DISABLED_TSDTest) {
+  pthread_t th;
+  pthread_key_t test_key;
+  pthread_key_create(&test_key, TSDDestructor);
+  pthread_create(&th, NULL, TSDWorker, &test_key);
+  pthread_join(th, NULL);
+  pthread_key_delete(test_key);
+}
+
+template<class T>
+void OOBTest() {
+  char expected_str[100];
+  for (int size = sizeof(T); size < 20; size += 5) {
+    for (int i = -5; i < 0; i++) {
+      const char *str =
+          "is located.*%d byte.*to the left";
+      sprintf(expected_str, str, abs(i));
+      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+    }
+
+    for (int i = 0; i < size - sizeof(T) + 1; i++)
+      oob_test<T>(size, i);
+
+    for (int i = size - sizeof(T) + 1; i <= size + 3 * sizeof(T); i++) {
+      const char *str =
+          "is located.*%d byte.*to the right";
+      int off = i >= size ? (i - size) : 0;
+      // we don't catch unaligned partially OOB accesses.
+      if (i % sizeof(T)) continue;
+      sprintf(expected_str, str, off);
+      EXPECT_DEATH(oob_test<T>(size, i), expected_str);
+    }
+  }
+
+  EXPECT_DEATH(oob_test<T>(kLargeMalloc, -1),
+          "is located.*1 byte.*to the left");
+  EXPECT_DEATH(oob_test<T>(kLargeMalloc, kLargeMalloc),
+          "is located.*0 byte.*to the right");
+}
+
+// TODO(glider): the following tests are EXTREMELY slow on Darwin:
+//   AddressSanitizer.OOB_char (125503 ms)
+//   AddressSanitizer.OOB_int (126890 ms)
+//   AddressSanitizer.OOBRightTest (315605 ms)
+//   AddressSanitizer.SimpleStackTest (366559 ms)
+
+TEST(AddressSanitizer, OOB_char) {
+  OOBTest<U1>();
+}
+
+TEST(AddressSanitizer, OOB_int) {
+  OOBTest<U4>();
+}
+
+TEST(AddressSanitizer, OOBRightTest) {
+  for (size_t access_size = 1; access_size <= 8; access_size *= 2) {
+    for (size_t alloc_size = 1; alloc_size <= 8; alloc_size++) {
+      for (size_t offset = 0; offset <= 8; offset += access_size) {
+        void *p = malloc(alloc_size);
+        // allocated: [p, p + alloc_size)
+        // accessed:  [p + offset, p + offset + access_size)
+        uint8_t *addr = (uint8_t*)p + offset;
+        if (offset + access_size <= alloc_size) {
+          asan_write_sized_aligned(addr, access_size);
+        } else {
+          int outside_bytes = offset > alloc_size ? (offset - alloc_size) : 0;
+          const char *str =
+              "is located.%d *byte.*to the right";
+          char expected_str[100];
+          sprintf(expected_str, str, outside_bytes);
+          EXPECT_DEATH(asan_write_sized_aligned(addr, access_size),
+                       expected_str);
+        }
+        free(p);
+      }
+    }
+  }
+}
+
+TEST(AddressSanitizer, UAF_char) {
+  const char *uaf_string = "AddressSanitizer.*heap-use-after-free";
+  EXPECT_DEATH(uaf_test<U1>(1, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(10, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(10, 10), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, 0), uaf_string);
+  EXPECT_DEATH(uaf_test<U1>(kLargeMalloc, kLargeMalloc / 2), uaf_string);
+}
+
+#if ASAN_HAS_BLACKLIST
+TEST(AddressSanitizer, IgnoreTest) {
+  int *x = Ident(new int);
+  delete Ident(x);
+  *x = 0;
+}
+#endif  // ASAN_HAS_BLACKLIST
+
+struct StructWithBitField {
+  int bf1:1;
+  int bf2:1;
+  int bf3:1;
+  int bf4:29;
+};
+
+TEST(AddressSanitizer, BitFieldPositiveTest) {
+  StructWithBitField *x = new StructWithBitField;
+  delete Ident(x);
+  EXPECT_DEATH(x->bf1 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf2 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf3 = 0, "use-after-free");
+  EXPECT_DEATH(x->bf4 = 0, "use-after-free");
+};
+
+struct StructWithBitFields_8_24 {
+  int a:8;
+  int b:24;
+};
+
+TEST(AddressSanitizer, BitFieldNegativeTest) {
+  StructWithBitFields_8_24 *x = Ident(new StructWithBitFields_8_24);
+  x->a = 0;
+  x->b = 0;
+  delete Ident(x);
+}
+
+TEST(AddressSanitizer, OutOfMemoryTest) {
+  size_t size = __WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000);
+  EXPECT_EQ(0, realloc(0, size));
+  EXPECT_EQ(0, realloc(0, ~Ident(0)));
+  EXPECT_EQ(0, malloc(size));
+  EXPECT_EQ(0, malloc(~Ident(0)));
+  EXPECT_EQ(0, calloc(1, size));
+  EXPECT_EQ(0, calloc(1, ~Ident(0)));
+}
+
+#if ASAN_NEEDS_SEGV
+TEST(AddressSanitizer, WildAddressTest) {
+  char *c = (char*)0x123;
+  EXPECT_DEATH(*c = 0, "AddressSanitizer crashed on unknown address");
+}
+#endif
+
+static void MallocStress(size_t n) {
+  uint32_t seed = my_rand(&global_seed);
+  for (size_t iter = 0; iter < 10; iter++) {
+    vector<void *> vec;
+    for (size_t i = 0; i < n; i++) {
+      if ((i % 3) == 0) {
+        if (vec.empty()) continue;
+        size_t idx = my_rand(&seed) % vec.size();
+        void *ptr = vec[idx];
+        vec[idx] = vec.back();
+        vec.pop_back();
+        free_aaa(ptr);
+      } else {
+        size_t size = my_rand(&seed) % 1000 + 1;
+#ifndef __APPLE__
+        size_t alignment = 1 << (my_rand(&seed) % 7 + 3);
+        char *ptr = (char*)memalign_aaa(alignment, size);
+#else
+        char *ptr = (char*) malloc_aaa(size);
+#endif
+        vec.push_back(ptr);
+        ptr[0] = 0;
+        ptr[size-1] = 0;
+        ptr[size/2] = 0;
+      }
+    }
+    for (size_t i = 0; i < vec.size(); i++)
+      free_aaa(vec[i]);
+  }
+}
+
+TEST(AddressSanitizer, MallocStressTest) {
+  MallocStress(200000);
+}
+
+static void TestLargeMalloc(size_t size) {
+  char buff[1024];
+  sprintf(buff, "is located 1 bytes to the left of %lu-byte", (long)size);
+  EXPECT_DEATH(Ident((char*)malloc(size))[-1] = 0, buff);
+}
+
+TEST(AddressSanitizer, LargeMallocTest) {
+  for (int i = 113; i < (1 << 28); i = i * 2 + 13) {
+    TestLargeMalloc(i);
+  }
+}
+
+TEST(AddressSanitizer, HugeMallocTest) {
+#ifdef __APPLE__
+  // It was empirically found out that 1215 megabytes is the maximum amount of
+  // memory available to the process under AddressSanitizer on Darwin.
+  // (the libSystem malloc() allows allocating up to 2300 megabytes without
+  // ASan).
+  size_t n_megs = __WORDSIZE == 32 ? 1200 : 4100;
+#else
+  size_t n_megs = __WORDSIZE == 32 ? 2600 : 4100;
+#endif
+  TestLargeMalloc(n_megs << 20);
+}
+
+TEST(AddressSanitizer, ThreadedMallocStressTest) {
+  const int kNumThreads = 4;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))MallocStress, (void*)100000);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+void *ManyThreadsWorker(void *a) {
+  for (int iter = 0; iter < 100; iter++) {
+    for (size_t size = 100; size < 2000; size *= 2) {
+      free(Ident(malloc(size)));
+    }
+  }
+  return 0;
+}
+
+TEST(AddressSanitizer, ManyThreadsTest) {
+  const size_t kNumThreads = __WORDSIZE == 32 ? 150 : 1000;
+  pthread_t t[kNumThreads];
+  for (size_t i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))ManyThreadsWorker, (void*)i);
+  }
+  for (size_t i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+TEST(AddressSanitizer, ReallocTest) {
+  const int kMinElem = 5;
+  int *ptr = (int*)malloc(sizeof(int) * kMinElem);
+  ptr[3] = 3;
+  for (int i = 0; i < 10000; i++) {
+    ptr = (int*)realloc(ptr,
+        (my_rand(&global_seed) % 1000 + kMinElem) * sizeof(int));
+    EXPECT_EQ(3, ptr[3]);
+  }
+}
+
+void WrongFree() {
+  int *x = (int*)malloc(100 * sizeof(int));
+  // Use the allocated memory, otherwise Clang will optimize it out.
+  Ident(x);
+  free(x + 1);
+}
+
+TEST(AddressSanitizer, WrongFreeTest) {
+  EXPECT_DEATH(WrongFree(), "attempting free.*not malloc");
+}
+
+void DoubleFree() {
+  int *x = (int*)malloc(100 * sizeof(int));
+  fprintf(stderr, "DoubleFree: x=%p\n", x);
+  free(x);
+  free(x);
+  fprintf(stderr, "should have failed in the second free(%p)\n", x);
+  abort();
+}
+
+TEST(AddressSanitizer, DoubleFreeTest) {
+  EXPECT_DEATH(DoubleFree(), "attempting double-free");
+}
+
+template<int kSize>
+__attribute__((noinline))
+void SizedStackTest() {
+  char a[kSize];
+  char  *A = Ident((char*)&a);
+  for (size_t i = 0; i < kSize; i++)
+    A[i] = i;
+  EXPECT_DEATH(A[-1] = 0, "");
+  EXPECT_DEATH(A[-20] = 0, "");
+  EXPECT_DEATH(A[-31] = 0, "");
+  EXPECT_DEATH(A[kSize] = 0, "");
+  EXPECT_DEATH(A[kSize + 1] = 0, "");
+  EXPECT_DEATH(A[kSize + 10] = 0, "");
+  EXPECT_DEATH(A[kSize + 31] = 0, "");
+}
+
+TEST(AddressSanitizer, SimpleStackTest) {
+  SizedStackTest<1>();
+  SizedStackTest<2>();
+  SizedStackTest<3>();
+  SizedStackTest<4>();
+  SizedStackTest<5>();
+  SizedStackTest<6>();
+  SizedStackTest<7>();
+  SizedStackTest<16>();
+  SizedStackTest<25>();
+  SizedStackTest<34>();
+  SizedStackTest<43>();
+  SizedStackTest<51>();
+  SizedStackTest<62>();
+  SizedStackTest<64>();
+  SizedStackTest<128>();
+}
+
+TEST(AddressSanitizer, ManyStackObjectsTest) {
+  char XXX[10];
+  char YYY[20];
+  char ZZZ[30];
+  Ident(XXX);
+  Ident(YYY);
+  EXPECT_DEATH(Ident(ZZZ)[-1] = 0, ASAN_PCRE_DOTALL "XXX.*YYY.*ZZZ");
+}
+
+__attribute__((noinline))
+static void Frame0(int frame, char *a, char *b, char *c) {
+  char d[4] = {0};
+  char *D = Ident(d);
+  switch (frame) {
+    case 3: a[5]++; break;
+    case 2: b[5]++; break;
+    case 1: c[5]++; break;
+    case 0: D[5]++; break;
+  }
+}
+__attribute__((noinline)) static void Frame1(int frame, char *a, char *b) {
+  char c[4] = {0}; Frame0(frame, a, b, c);
+  break_optimization(0);
+}
+__attribute__((noinline)) static void Frame2(int frame, char *a) {
+  char b[4] = {0}; Frame1(frame, a, b);
+  break_optimization(0);
+}
+__attribute__((noinline)) static void Frame3(int frame) {
+  char a[4] = {0}; Frame2(frame, a);
+  break_optimization(0);
+}
+
+TEST(AddressSanitizer, GuiltyStackFrame0Test) {
+  EXPECT_DEATH(Frame3(0), "located .*in frame <.*Frame0");
+}
+TEST(AddressSanitizer, GuiltyStackFrame1Test) {
+  EXPECT_DEATH(Frame3(1), "located .*in frame <.*Frame1");
+}
+TEST(AddressSanitizer, GuiltyStackFrame2Test) {
+  EXPECT_DEATH(Frame3(2), "located .*in frame <.*Frame2");
+}
+TEST(AddressSanitizer, GuiltyStackFrame3Test) {
+  EXPECT_DEATH(Frame3(3), "located .*in frame <.*Frame3");
+}
+
+__attribute__((noinline))
+void LongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  longjmp(buf, 1);
+}
+
+__attribute__((noinline))
+void UnderscopeLongJmpFunc1(jmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  _longjmp(buf, 1);
+}
+
+__attribute__((noinline))
+void SigLongJmpFunc1(sigjmp_buf buf) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  siglongjmp(buf, 1);
+}
+
+
+__attribute__((noinline))
+void TouchStackFunc() {
+  int a[100];  // long array will intersect with redzones from LongJmpFunc1.
+  int *A = Ident(a);
+  for (int i = 0; i < 100; i++)
+    A[i] = i*i;
+}
+
+// Test that we handle longjmp and do not report fals positives on stack.
+TEST(AddressSanitizer, LongJmpTest) {
+  static jmp_buf buf;
+  if (!setjmp(buf)) {
+    LongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+TEST(AddressSanitizer, UnderscopeLongJmpTest) {
+  static jmp_buf buf;
+  if (!_setjmp(buf)) {
+    UnderscopeLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+TEST(AddressSanitizer, SigLongJmpTest) {
+  static sigjmp_buf buf;
+  if (!sigsetjmp(buf, 1)) {
+    SigLongJmpFunc1(buf);
+  } else {
+    TouchStackFunc();
+  }
+}
+
+#ifdef __EXCEPTIONS
+__attribute__((noinline))
+void ThrowFunc() {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  ASAN_THROW(1);
+}
+
+TEST(AddressSanitizer, CxxExceptionTest) {
+  if (ASAN_UAR) return;
+  // TODO(kcc): this test crashes on 32-bit for some reason...
+  if (__WORDSIZE == 32) return;
+  try {
+    ThrowFunc();
+  } catch(...) {}
+  TouchStackFunc();
+}
+#endif
+
+void *ThreadStackReuseFunc1(void *unused) {
+  // create three red zones for these two stack objects.
+  int a;
+  int b;
+
+  int *A = Ident(&a);
+  int *B = Ident(&b);
+  *A = *B;
+  pthread_exit(0);
+  return 0;
+}
+
+void *ThreadStackReuseFunc2(void *unused) {
+  TouchStackFunc();
+  return 0;
+}
+
+TEST(AddressSanitizer, ThreadStackReuseTest) {
+  pthread_t t;
+  pthread_create(&t, 0, ThreadStackReuseFunc1, 0);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadStackReuseFunc2, 0);
+  pthread_join(t, 0);
+}
+
+#if defined(__i386__) or defined(__x86_64__)
+TEST(AddressSanitizer, Store128Test) {
+  char *a = Ident((char*)malloc(Ident(12)));
+  char *p = a;
+  if (((uintptr_t)a % 16) != 0)
+    p = a + 8;
+  assert(((uintptr_t)p % 16) == 0);
+  __m128i value_wide = _mm_set1_epi16(0x1234);
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "WRITE of size 16");
+  EXPECT_DEATH(_mm_store_si128((__m128i*)p, value_wide),
+               "located 0 bytes to the right of 12-byte");
+  free(a);
+}
+#endif
+
+static string RightOOBErrorMessage(int oob_distance) {
+  assert(oob_distance >= 0);
+  char expected_str[100];
+  sprintf(expected_str, "located %d bytes to the right", oob_distance);
+  return string(expected_str);
+}
+
+static string LeftOOBErrorMessage(int oob_distance) {
+  assert(oob_distance > 0);
+  char expected_str[100];
+  sprintf(expected_str, "located %d bytes to the left", oob_distance);
+  return string(expected_str);
+}
+
+template<class T>
+void MemSetOOBTestTemplate(size_t length) {
+  if (length == 0) return;
+  size_t size = Ident(sizeof(T) * length);
+  T *array = Ident((T*)malloc(size));
+  int element = Ident(42);
+  int zero = Ident(0);
+  // memset interval inside array
+  memset(array, element, size);
+  memset(array, element, size - 1);
+  memset(array + length - 1, element, sizeof(T));
+  memset(array, element, 1);
+
+  // memset 0 bytes
+  memset(array - 10, element, zero);
+  memset(array - 1, element, zero);
+  memset(array, element, zero);
+  memset(array + length, 0, zero);
+  memset(array + length + 1, 0, zero);
+
+  // try to memset bytes to the right of array
+  EXPECT_DEATH(memset(array, 0, size + 1),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(memset((char*)(array + length) - 1, element, 6),
+               RightOOBErrorMessage(4));
+  EXPECT_DEATH(memset(array + 1, element, size + sizeof(T)),
+               RightOOBErrorMessage(2 * sizeof(T) - 1));
+  // whole interval is to the right
+  EXPECT_DEATH(memset(array + length + 1, 0, 10),
+               RightOOBErrorMessage(sizeof(T)));
+
+  // try to memset bytes to the left of array
+  EXPECT_DEATH(memset((char*)array - 1, element, size),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(memset((char*)array - 5, 0, 6),
+               LeftOOBErrorMessage(5));
+  EXPECT_DEATH(memset(array - 5, element, size + 5 * sizeof(T)),
+               LeftOOBErrorMessage(5 * sizeof(T)));
+  // whole interval is to the left
+  EXPECT_DEATH(memset(array - 2, 0, sizeof(T)),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+
+  // try to memset bytes both to the left & to the right
+  EXPECT_DEATH(memset((char*)array - 2, element, size + 4),
+               LeftOOBErrorMessage(2));
+
+  free(array);
+}
+
+TEST(AddressSanitizer, MemSetOOBTest) {
+  MemSetOOBTestTemplate<char>(100);
+  MemSetOOBTestTemplate<int>(5);
+  MemSetOOBTestTemplate<double>(256);
+  // We can test arrays of structres/classes here, but what for?
+}
+
+// Same test for memcpy and memmove functions
+template <class T, class M>
+void MemTransferOOBTestTemplate(size_t length) {
+  if (length == 0) return;
+  size_t size = Ident(sizeof(T) * length);
+  T *src = Ident((T*)malloc(size));
+  T *dest = Ident((T*)malloc(size));
+  int zero = Ident(0);
+
+  // valid transfer of bytes between arrays
+  M::transfer(dest, src, size);
+  M::transfer(dest + 1, src, size - sizeof(T));
+  M::transfer(dest, src + length - 1, sizeof(T));
+  M::transfer(dest, src, 1);
+
+  // transfer zero bytes
+  M::transfer(dest - 1, src, 0);
+  M::transfer(dest + length, src, zero);
+  M::transfer(dest, src - 1, zero);
+  M::transfer(dest, src, zero);
+
+  // try to change mem to the right of dest
+  EXPECT_DEATH(M::transfer(dest + 1, src, size),
+               RightOOBErrorMessage(sizeof(T) - 1));
+  EXPECT_DEATH(M::transfer((char*)(dest + length) - 1, src, 5),
+               RightOOBErrorMessage(3));
+
+  // try to change mem to the left of dest
+  EXPECT_DEATH(M::transfer(dest - 2, src, size),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+  EXPECT_DEATH(M::transfer((char*)dest - 3, src, 4),
+               LeftOOBErrorMessage(3));
+
+  // try to access mem to the right of src
+  EXPECT_DEATH(M::transfer(dest, src + 2, size),
+               RightOOBErrorMessage(2 * sizeof(T) - 1));
+  EXPECT_DEATH(M::transfer(dest, (char*)(src + length) - 3, 6),
+               RightOOBErrorMessage(2));
+
+  // try to access mem to the left of src
+  EXPECT_DEATH(M::transfer(dest, src - 1, size),
+               LeftOOBErrorMessage(sizeof(T)));
+  EXPECT_DEATH(M::transfer(dest, (char*)src - 6, 7),
+               LeftOOBErrorMessage(6));
+
+  // Generally we don't need to test cases where both accessing src and writing
+  // to dest address to poisoned memory.
+
+  T *big_src = Ident((T*)malloc(size * 2));
+  T *big_dest = Ident((T*)malloc(size * 2));
+  // try to change mem to both sides of dest
+  EXPECT_DEATH(M::transfer(dest - 1, big_src, size * 2),
+               LeftOOBErrorMessage(sizeof(T)));
+  // try to access mem to both sides of src
+  EXPECT_DEATH(M::transfer(big_dest, src - 2, size * 2),
+               LeftOOBErrorMessage(2 * sizeof(T)));
+
+  free(src);
+  free(dest);
+  free(big_src);
+  free(big_dest);
+}
+
+class MemCpyWrapper {
+ public:
+  static void* transfer(void *to, const void *from, size_t size) {
+    return memcpy(to, from, size);
+  }
+};
+TEST(AddressSanitizer, MemCpyOOBTest) {
+  MemTransferOOBTestTemplate<char, MemCpyWrapper>(100);
+  MemTransferOOBTestTemplate<int, MemCpyWrapper>(1024);
+}
+
+class MemMoveWrapper {
+ public:
+  static void* transfer(void *to, const void *from, size_t size) {
+    return memmove(to, from, size);
+  }
+};
+TEST(AddressSanitizer, MemMoveOOBTest) {
+  MemTransferOOBTestTemplate<char, MemMoveWrapper>(100);
+  MemTransferOOBTestTemplate<int, MemMoveWrapper>(1024);
+}
+
+// Tests for string functions
+
+// Used for string functions tests
+static char global_string[] = "global";
+static size_t global_string_length = 6;
+
+// Input to a test is a zero-terminated string str with given length
+// Accesses to the bytes to the left and to the right of str
+// are presumed to produce OOB errors
+void StrLenOOBTestTemplate(char *str, size_t length, bool is_global) {
+  // Normal strlen calls
+  EXPECT_EQ(strlen(str), length);
+  if (length > 0) {
+    EXPECT_EQ(strlen(str + 1), length - 1);
+    EXPECT_EQ(strlen(str + length), 0);
+  }
+  // Arg of strlen is not malloced, OOB access
+  if (!is_global) {
+    // We don't insert RedZones to the left of global variables
+    EXPECT_DEATH(Ident(strlen(str - 1)), LeftOOBErrorMessage(1));
+    EXPECT_DEATH(Ident(strlen(str - 5)), LeftOOBErrorMessage(5));
+  }
+  EXPECT_DEATH(Ident(strlen(str + length + 1)), RightOOBErrorMessage(0));
+  // Overwrite terminator
+  str[length] = 'a';
+  // String is not zero-terminated, strlen will lead to OOB access
+  EXPECT_DEATH(Ident(strlen(str)), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strlen(str + length)), RightOOBErrorMessage(0));
+  // Restore terminator
+  str[length] = 0;
+}
+TEST(AddressSanitizer, StrLenOOBTest) {
+  // Check heap-allocated string
+  size_t length = Ident(10);
+  char *heap_string = Ident((char*)malloc(length + 1));
+  char stack_string[10 + 1];
+  for (int i = 0; i < length; i++) {
+    heap_string[i] = 'a';
+    stack_string[i] = 'b';
+  }
+  heap_string[length] = 0;
+  stack_string[length] = 0;
+  StrLenOOBTestTemplate(heap_string, length, false);
+  // TODO(samsonov): Fix expected messages in StrLenOOBTestTemplate to
+  //      make test for stack_string work. Or move it to output tests.
+  // StrLenOOBTestTemplate(stack_string, length, false);
+  StrLenOOBTestTemplate(global_string, global_string_length, true);
+  free(heap_string);
+}
+
+#ifndef __APPLE__
+TEST(AddressSanitizer, StrNLenOOBTest) {
+  size_t size = Ident(123);
+  char *str = Ident((char*)malloc(size));
+  memset(str, 'z', size);
+  // Normal strnlen calls.
+  Ident(strnlen(str - 1, 0));
+  Ident(strnlen(str, size));
+  Ident(strnlen(str + size - 1, 1));
+  str[size - 1] = '\0';
+  Ident(strnlen(str, 2 * size));
+  // Argument points to not allocated memory.
+  EXPECT_DEATH(Ident(strnlen(str - 1, 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strnlen(str + size, 1)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' and hit unallocated memory.
+  str[size - 1] = 'z';
+  EXPECT_DEATH(Ident(strnlen(str, size + 1)), RightOOBErrorMessage(0));
+  free(str);
+}
+#endif
+
+TEST(AddressSanitizer, StrDupOOBTest) {
+  size_t size = Ident(42);
+  char *str = Ident((char*)malloc(size));
+  char *new_str;
+  memset(str, 'z', size);
+  // Normal strdup calls.
+  str[size - 1] = '\0';
+  new_str = strdup(str);
+  free(new_str);
+  new_str = strdup(str + size - 1);
+  free(new_str);
+  // Argument points to not allocated memory.
+  EXPECT_DEATH(Ident(strdup(str - 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strdup(str + size)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' and hit unallocated memory.
+  str[size - 1] = 'z';
+  EXPECT_DEATH(Ident(strdup(str)), RightOOBErrorMessage(0));
+  free(str);
+}
+
+TEST(AddressSanitizer, StrCpyOOBTest) {
+  size_t to_size = Ident(30);
+  size_t from_size = Ident(6);  // less than to_size
+  char *to = Ident((char*)malloc(to_size));
+  char *from = Ident((char*)malloc(from_size));
+  // Normal strcpy calls.
+  strcpy(from, "hello");
+  strcpy(to, from);
+  strcpy(to + to_size - from_size, from);
+  // Length of "from" is too small.
+  EXPECT_DEATH(Ident(strcpy(from, "hello2")), RightOOBErrorMessage(0));
+  // "to" or "from" points to not allocated memory.
+  EXPECT_DEATH(Ident(strcpy(to - 1, from)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcpy(to, from - 1)), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcpy(to, from + from_size)), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strcpy(to + to_size, from)), RightOOBErrorMessage(0));
+  // Overwrite the terminating '\0' character and hit unallocated memory.
+  from[from_size - 1] = '!';
+  EXPECT_DEATH(Ident(strcpy(to, from)), RightOOBErrorMessage(0));
+  free(to);
+  free(from);
+}
+
+TEST(AddressSanitizer, StrNCpyOOBTest) {
+  size_t to_size = Ident(20);
+  size_t from_size = Ident(6);  // less than to_size
+  char *to = Ident((char*)malloc(to_size));
+  // From is a zero-terminated string "hello\0" of length 6
+  char *from = Ident((char*)malloc(from_size));
+  strcpy(from, "hello");
+  // copy 0 bytes
+  strncpy(to, from, 0);
+  strncpy(to - 1, from - 1, 0);
+  // normal strncpy calls
+  strncpy(to, from, from_size);
+  strncpy(to, from, to_size);
+  strncpy(to, from + from_size - 1, to_size);
+  strncpy(to + to_size - 1, from, 1);
+  // One of {to, from} points to not allocated memory
+  EXPECT_DEATH(Ident(strncpy(to, from - 1, from_size)),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncpy(to - 1, from, from_size)),
+               LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncpy(to, from + from_size, 1)),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncpy(to + to_size, from, 1)),
+               RightOOBErrorMessage(0));
+  // Length of "to" is too small
+  EXPECT_DEATH(Ident(strncpy(to + to_size - from_size + 1, from, from_size)),
+               RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncpy(to + 1, from, to_size)),
+               RightOOBErrorMessage(0));
+  // Overwrite terminator in from
+  from[from_size - 1] = '!';
+  // normal strncpy call
+  strncpy(to, from, from_size);
+  // Length of "from" is too small
+  EXPECT_DEATH(Ident(strncpy(to, from, to_size)),
+               RightOOBErrorMessage(0));
+  free(to);
+  free(from);
+}
+
+typedef char*(*PointerToStrChr)(const char*, int);
+void RunStrChrTest(PointerToStrChr StrChr) {
+  size_t size = Ident(100);
+  char *str = Ident((char*)malloc(size));
+  memset(str, 'z', size);
+  str[10] = 'q';
+  str[11] = '\0';
+  EXPECT_EQ(str, StrChr(str, 'z'));
+  EXPECT_EQ(str + 10, StrChr(str, 'q'));
+  EXPECT_EQ(NULL, StrChr(str, 'a'));
+  // StrChr argument points to not allocated memory.
+  EXPECT_DEATH(Ident(StrChr(str - 1, 'z')), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(StrChr(str + size, 'z')), RightOOBErrorMessage(0));
+  // Overwrite the terminator and hit not allocated memory.
+  str[11] = 'z';
+  EXPECT_DEATH(Ident(StrChr(str, 'a')), RightOOBErrorMessage(0));
+  free(str);
+}
+TEST(AddressSanitizer, StrChrAndIndexOOBTest) {
+  RunStrChrTest(&strchr);
+  RunStrChrTest(&index);
+}
+
+TEST(AddressSanitizer, StrCmpAndFriendsLogicTest) {
+  // strcmp
+  EXPECT_EQ(0, strcmp("", ""));
+  EXPECT_EQ(0, strcmp("abcd", "abcd"));
+  EXPECT_EQ(-1, strcmp("ab", "ac"));
+  EXPECT_EQ(-1, strcmp("abc", "abcd"));
+  EXPECT_EQ(1, strcmp("acc", "abc"));
+  EXPECT_EQ(1, strcmp("abcd", "abc"));
+
+  // strncmp
+  EXPECT_EQ(0, strncmp("a", "b", 0));
+  EXPECT_EQ(0, strncmp("abcd", "abcd", 10));
+  EXPECT_EQ(0, strncmp("abcd", "abcef", 3));
+  EXPECT_EQ(-1, strncmp("abcde", "abcfa", 4));
+  EXPECT_EQ(-1, strncmp("a", "b", 5));
+  EXPECT_EQ(-1, strncmp("bc", "bcde", 4));
+  EXPECT_EQ(1, strncmp("xyz", "xyy", 10));
+  EXPECT_EQ(1, strncmp("baa", "aaa", 1));
+  EXPECT_EQ(1, strncmp("zyx", "", 2));
+}
+
+static inline char* MallocAndMemsetString(size_t size) {
+  char *s = Ident((char*)malloc(size));
+  memset(s, 'z', size);
+  return s;
+}
+
+TEST(AddressSanitizer, StrCmpOOBTest) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  // Normal strcmp calls
+  Ident(strcmp(s1, s2));
+  Ident(strcmp(s1, s2 + size - 1));
+  Ident(strcmp(s1 + size - 1, s2 + size - 1));
+  s1[size - 1] = 'z';
+  s2[size - 1] = 'x';
+  Ident(strcmp(s1, s2));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(strcmp)(s1 - 1, s2), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcmp)(s1, s2 - 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strcmp)(s1 + size, s2), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strcmp)(s1, s2 + size), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  s2[size - 1] = 'z';
+  EXPECT_DEATH(Ident(strcmp)(s1, s1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strcmp)(s1 + size - 1, s2), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+TEST(AddressSanitizer, StrNCmpOOBTest) {
+  size_t size = Ident(100);
+  char *s1 = MallocAndMemsetString(size);
+  char *s2 = MallocAndMemsetString(size);
+  s1[size - 1] = '\0';
+  s2[size - 1] = '\0';
+  // Normal strncmp calls
+  Ident(strncmp(s1, s2, size + 2));
+  s1[size - 1] = 'z';
+  s2[size - 1] = 'x';
+  Ident(strncmp(s1 + size - 2, s2 + size - 2, size));
+  s2[size - 1] = 'z';
+  Ident(strncmp(s1 - 1, s2 - 1, 0));
+  Ident(strncmp(s1 + size - 1, s2 + size - 1, 1));
+  // One of arguments points to not allocated memory.
+  EXPECT_DEATH(Ident(strncmp)(s1 - 1, s2, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncmp)(s1, s2 - 1, 1), LeftOOBErrorMessage(1));
+  EXPECT_DEATH(Ident(strncmp)(s1 + size, s2, 1), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncmp)(s1, s2 + size, 1), RightOOBErrorMessage(0));
+  // Hit unallocated memory and die.
+  EXPECT_DEATH(Ident(strncmp)(s1 + 1, s2 + 1, size), RightOOBErrorMessage(0));
+  EXPECT_DEATH(Ident(strncmp)(s1 + size - 1, s2, 2), RightOOBErrorMessage(0));
+  free(s1);
+  free(s2);
+}
+
+static const char *kOverlapErrorMessage = "strcpy-param-overlap";
+
+TEST(AddressSanitizer, StrArgsOverlapTest) {
+  size_t size = Ident(100);
+  char *str = Ident((char*)malloc(size));
+
+#if 0
+  // Check "memcpy". Use Ident() to avoid inlining.
+  memset(str, 'z', size);
+  Ident(memcpy)(str + 1, str + 11, 10);
+  Ident(memcpy)(str, str, 0);
+  EXPECT_DEATH(Ident(memcpy)(str, str + 14, 15), kOverlapErrorMessage);
+  EXPECT_DEATH(Ident(memcpy)(str + 14, str, 15), kOverlapErrorMessage);
+  EXPECT_DEATH(Ident(memcpy)(str + 20, str + 20, 1), kOverlapErrorMessage);
+#endif
+
+  // Check "strcpy".
+  memset(str, 'z', size);
+  str[9] = '\0';
+  strcpy(str + 10, str);
+  EXPECT_DEATH(strcpy(str + 9, str), kOverlapErrorMessage);
+  EXPECT_DEATH(strcpy(str, str + 4), kOverlapErrorMessage);
+  strcpy(str, str + 5);
+
+  // Check "strncpy".
+  memset(str, 'z', size);
+  strncpy(str, str + 10, 10);
+  EXPECT_DEATH(strncpy(str, str + 9, 10), kOverlapErrorMessage);
+  EXPECT_DEATH(strncpy(str + 9, str, 10), kOverlapErrorMessage);
+  str[10] = '\0';
+  strncpy(str + 11, str, 20);
+  EXPECT_DEATH(strncpy(str + 10, str, 20), kOverlapErrorMessage);
+
+  free(str);
+}
+
+// At the moment we instrument memcpy/memove/memset calls at compile time so we
+// can't handle OOB error if these functions are called by pointer, see disabled
+// MemIntrinsicCallByPointerTest below
+typedef void*(*PointerToMemTransfer)(void*, const void*, size_t);
+typedef void*(*PointerToMemSet)(void*, int, size_t);
+
+void CallMemSetByPointer(PointerToMemSet MemSet) {
+  size_t size = Ident(100);
+  char *array = Ident((char*)malloc(size));
+  EXPECT_DEATH(MemSet(array, 0, 101), RightOOBErrorMessage(0));
+  free(array);
+}
+
+void CallMemTransferByPointer(PointerToMemTransfer MemTransfer) {
+  size_t size = Ident(100);
+  char *src = Ident((char*)malloc(size));
+  char *dst = Ident((char*)malloc(size));
+  EXPECT_DEATH(MemTransfer(dst, src, 101), RightOOBErrorMessage(0));
+  free(src);
+  free(dst);
+}
+
+TEST(AddressSanitizer, DISABLED_MemIntrinsicCallByPointerTest) {
+  CallMemSetByPointer(&memset);
+  CallMemTransferByPointer(&memcpy);
+  CallMemTransferByPointer(&memmove);
+}
+
+// This test case fails
+// Clang optimizes memcpy/memset calls which lead to unaligned access
+TEST(AddressSanitizer, DISABLED_MemIntrinsicUnalignedAccessTest) {
+  int size = Ident(4096);
+  char *s = Ident((char*)malloc(size));
+  EXPECT_DEATH(memset(s + size - 1, 0, 2), RightOOBErrorMessage(0));
+  free(s);
+}
+
+// TODO(samsonov): Add a test with malloc(0)
+// TODO(samsonov): Add tests for str* and mem* functions.
+
+__attribute__((noinline))
+static int LargeFunction(bool do_bad_access) {
+  int *x = new int[100];
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  x[do_bad_access ? 100 : 0]++; int res = __LINE__;
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+
+  delete x;
+  return res;
+}
+
+// Test the we have correct debug info for the failing instruction.
+// This test requires the in-process symbolizer to be enabled by default.
+TEST(AddressSanitizer, DISABLED_LargeFunctionSymbolizeTest) {
+  int failing_line = LargeFunction(false);
+  char expected_warning[128];
+  sprintf(expected_warning, "LargeFunction.*asan_test.cc:%d", failing_line);
+  EXPECT_DEATH(LargeFunction(true), expected_warning);
+}
+
+// Check that we unwind and symbolize correctly.
+TEST(AddressSanitizer, DISABLED_MallocFreeUnwindAndSymbolizeTest) {
+  int *a = (int*)malloc_aaa(sizeof(int));
+  *a = 1;
+  free_aaa(a);
+  EXPECT_DEATH(*a = 1, "free_ccc.*free_bbb.*free_aaa.*"
+               "malloc_fff.*malloc_eee.*malloc_ddd");
+}
+
+void *ThreadedTestAlloc(void *a) {
+  int **p = (int**)a;
+  *p = new int;
+  return 0;
+}
+
+void *ThreadedTestFree(void *a) {
+  int **p = (int**)a;
+  delete *p;
+  return 0;
+}
+
+void *ThreadedTestUse(void *a) {
+  int **p = (int**)a;
+  **p = 1;
+  return 0;
+}
+
+void ThreadedTestSpawn() {
+  pthread_t t;
+  int *x;
+  pthread_create(&t, 0, ThreadedTestAlloc, &x);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadedTestFree, &x);
+  pthread_join(t, 0);
+  pthread_create(&t, 0, ThreadedTestUse, &x);
+  pthread_join(t, 0);
+}
+
+TEST(AddressSanitizer, ThreadedTest) {
+  EXPECT_DEATH(ThreadedTestSpawn(),
+               ASAN_PCRE_DOTALL
+               "Thread T.*created"
+               ".*Thread T.*created"
+               ".*Thread T.*created");
+}
+
+#if ASAN_NEEDS_SEGV
+TEST(AddressSanitizer, ShadowGapTest) {
+#if __WORDSIZE == 32
+  char *addr = (char*)0x22000000;
+#else
+  char *addr = (char*)0x0000100000080000;
+#endif
+  EXPECT_DEATH(*addr = 1, "AddressSanitizer crashed on unknown");
+}
+#endif  // ASAN_NEEDS_SEGV
+
+extern "C" {
+__attribute__((noinline))
+static void UseThenFreeThenUse() {
+  char *x = Ident((char*)malloc(8));
+  *x = 1;
+  free_aaa(x);
+  *x = 2;
+}
+}
+
+TEST(AddressSanitizer, UseThenFreeThenUseTest) {
+  EXPECT_DEATH(UseThenFreeThenUse(), "freed by thread");
+}
+
+TEST(AddressSanitizer, StrDupTest) {
+  free(strdup(Ident("123")));
+}
+
+TEST(AddressSanitizer, ObjdumpTest) {
+  ObjdumpOfMyself *o = objdump_of_myself();
+  EXPECT_TRUE(o->IsCorrect());
+}
+
+extern "C" {
+__attribute__((noinline))
+static void DisasmSimple() {
+  Ident(0);
+}
+
+__attribute__((noinline))
+static void DisasmParamWrite(int *a) {
+  *a = 1;
+}
+
+__attribute__((noinline))
+static void DisasmParamInc(int *a) {
+  (*a)++;
+}
+
+__attribute__((noinline))
+static void DisasmParamReadIfWrite(int *a) {
+  if (*a)
+    *a = 1;
+}
+
+__attribute__((noinline))
+static int DisasmParamIfReadWrite(int *a, int cond) {
+  int res = 0;
+  if (cond)
+    res = *a;
+  *a = 0;
+  return res;
+}
+
+static int GLOBAL;
+
+__attribute__((noinline))
+static void DisasmWriteGlob() {
+  GLOBAL = 1;
+}
+}  // extern "C"
+
+TEST(AddressSanitizer, DisasmTest) {
+  int a;
+  DisasmSimple();
+  DisasmParamWrite(&a);
+  DisasmParamInc(&a);
+  Ident(DisasmWriteGlob)();
+  DisasmParamReadIfWrite(&a);
+
+  a = 7;
+  EXPECT_EQ(7, DisasmParamIfReadWrite(&a, Ident(1)));
+  EXPECT_EQ(0, a);
+
+  ObjdumpOfMyself *o = objdump_of_myself();
+  vector<string> insns;
+  insns.push_back("ud2");
+  insns.push_back("__asan_report_");
+  EXPECT_EQ(0, o->CountInsnInFunc("DisasmSimple", insns));
+  EXPECT_EQ(1, o->CountInsnInFunc("DisasmParamWrite", insns));
+  EXPECT_EQ(1, o->CountInsnInFunc("DisasmParamInc", insns));
+  EXPECT_EQ(0, o->CountInsnInFunc("DisasmWriteGlob", insns));
+
+  // TODO(kcc): implement these (needs just one __asan_report).
+  EXPECT_EQ(2, o->CountInsnInFunc("DisasmParamReadIfWrite", insns));
+  EXPECT_EQ(2, o->CountInsnInFunc("DisasmParamIfReadWrite", insns));
+}
+
+// Currently we create and poison redzone at right of global variables.
+char glob5[5];
+static char static110[110];
+const char ConstGlob[7] = {1, 2, 3, 4, 5, 6, 7};
+static const char StaticConstGlob[3] = {9, 8, 7};
+extern int GlobalsTest(int x);
+
+TEST(AddressSanitizer, GlobalTest) {
+  static char func_static15[15];
+
+  static char fs1[10];
+  static char fs2[10];
+  static char fs3[10];
+
+  glob5[Ident(0)] = 0;
+  glob5[Ident(1)] = 0;
+  glob5[Ident(2)] = 0;
+  glob5[Ident(3)] = 0;
+  glob5[Ident(4)] = 0;
+
+  EXPECT_DEATH(glob5[Ident(5)] = 0,
+               "0 bytes to the right of global variable.*glob5.* size 5");
+  EXPECT_DEATH(glob5[Ident(5+6)] = 0,
+               "6 bytes to the right of global variable.*glob5.* size 5");
+  Ident(static110);  // avoid optimizations
+  static110[Ident(0)] = 0;
+  static110[Ident(109)] = 0;
+  EXPECT_DEATH(static110[Ident(110)] = 0,
+               "0 bytes to the right of global variable");
+  EXPECT_DEATH(static110[Ident(110+7)] = 0,
+               "7 bytes to the right of global variable");
+
+  Ident(func_static15);  // avoid optimizations
+  func_static15[Ident(0)] = 0;
+  EXPECT_DEATH(func_static15[Ident(15)] = 0,
+               "0 bytes to the right of global variable");
+  EXPECT_DEATH(func_static15[Ident(15 + 9)] = 0,
+               "9 bytes to the right of global variable");
+
+  Ident(fs1);
+  Ident(fs2);
+  Ident(fs3);
+
+  // We don't create left redzones, so this is not 100% guaranteed to fail.
+  // But most likely will.
+  EXPECT_DEATH(fs2[Ident(-1)] = 0, "is located.*of global variable");
+
+  EXPECT_DEATH(Ident(Ident(ConstGlob)[8]),
+               "is located 1 bytes to the right of .*ConstGlob");
+  EXPECT_DEATH(Ident(Ident(StaticConstGlob)[5]),
+               "is located 2 bytes to the right of .*StaticConstGlob");
+
+  // call stuff from another file.
+  GlobalsTest(0);
+}
+
+TEST(AddressSanitizer, GlobalStringConstTest) {
+  static const char *zoo = "FOOBAR123";
+  const char *p = Ident(zoo);
+  EXPECT_DEATH(Ident(p[15]), "is ascii string 'FOOBAR123'");
+}
+
+int *ReturnsPointerToALocalObject() {
+  int a = 0;
+  return Ident(&a);
+}
+
+TEST(AddressSanitizer, LocalReferenceReturnTest) {
+  int *(*f)() = Ident(ReturnsPointerToALocalObject);
+  // Call f several times, only the first time should be reported.
+  f();
+  f();
+  f();
+  f();
+  if (ASAN_UAR) {
+    EXPECT_DEATH(*f() = 1, "is located.*in frame .*ReturnsPointerToALocal");
+  }
+}
+
+template <int kSize>
+__attribute__((noinline))
+static void FuncWithStack() {
+  char x[kSize];
+  Ident(x)[0] = 0;
+  Ident(x)[kSize-1] = 0;
+}
+
+static void LotsOfStackReuse() {
+  int LargeStack[10000];
+  Ident(LargeStack)[0] = 0;
+  for (int i = 0; i < 10000; i++) {
+    FuncWithStack<128 * 1>();
+    FuncWithStack<128 * 2>();
+    FuncWithStack<128 * 4>();
+    FuncWithStack<128 * 8>();
+    FuncWithStack<128 * 16>();
+    FuncWithStack<128 * 32>();
+    FuncWithStack<128 * 64>();
+    FuncWithStack<128 * 128>();
+    FuncWithStack<128 * 256>();
+    FuncWithStack<128 * 512>();
+    Ident(LargeStack)[0] = 0;
+  }
+}
+
+TEST(AddressSanitizer, StressStackReuseTest) {
+  LotsOfStackReuse();
+}
+
+TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
+  const int kNumThreads = 20;
+  pthread_t t[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_create(&t[i], 0, (void* (*)(void *x))LotsOfStackReuse, 0);
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    pthread_join(t[i], 0);
+  }
+}
+
+#ifdef __EXCEPTIONS
+__attribute__((noinline))
+static void StackReuseAndException() {
+  int large_stack[1000];
+  Ident(large_stack);
+  ASAN_THROW(1);
+}
+
+// TODO(kcc): support exceptions with use-after-return.
+TEST(AddressSanitizer, DISABLED_StressStackReuseAndExceptionsTest) {
+  for (int i = 0; i < 10000; i++) {
+    try {
+    StackReuseAndException();
+    } catch(...) {
+    }
+  }
+}
+#endif
+
+TEST(AddressSanitizer, MlockTest) {
+  EXPECT_EQ(0, mlockall(MCL_CURRENT));
+  EXPECT_EQ(0, mlock((void*)0x12345, 0x5678));
+  EXPECT_EQ(0, munlockall());
+  EXPECT_EQ(0, munlock((void*)0x987, 0x654));
+}
+
+// ------------------ demo tests; run each one-by-one -------------
+// e.g. --gtest_filter=*DemoOOBLeftHigh --gtest_also_run_disabled_tests
+TEST(AddressSanitizer, DISABLED_DemoThreadedTest) {
+  ThreadedTestSpawn();
+}
+
+void *SimpleBugOnSTack(void *x = 0) {
+  char a[20];
+  Ident(a)[20] = 0;
+  return 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoStackTest) {
+  SimpleBugOnSTack();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoThreadStackTest) {
+  pthread_t t;
+  pthread_create(&t, 0, SimpleBugOnSTack, 0);
+  pthread_join(t, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFLowIn) {
+  uaf_test<U1>(10, 0);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowLeft) {
+  uaf_test<U1>(10, -2);
+}
+TEST(AddressSanitizer, DISABLED_DemoUAFLowRight) {
+  uaf_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoUAFHigh) {
+  uaf_test<U1>(kLargeMalloc, 0);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftLow) {
+  oob_test<U1>(10, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBLeftHigh) {
+  oob_test<U1>(kLargeMalloc, -1);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightLow) {
+  oob_test<U1>(10, 10);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOBRightHigh) {
+  oob_test<U1>(kLargeMalloc, kLargeMalloc);
+}
+
+TEST(AddressSanitizer, DISABLED_DemoOOM) {
+  size_t size = __WORDSIZE == 64 ? (size_t)(1ULL << 40) : (0xf0000000);
+  printf("%p\n", malloc(size));
+}
+
+TEST(AddressSanitizer, DISABLED_DemoDoubleFreeTest) {
+  DoubleFree();
+}
+
+TEST(AddressSanitizer, DISABLED_DemoNullDerefTest) {
+  int *a = 0;
+  Ident(a)[10] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoFunctionStaticTest) {
+  static char a[100];
+  static char b[100];
+  static char c[100];
+  Ident(a);
+  Ident(b);
+  Ident(c);
+  Ident(a)[5] = 0;
+  Ident(b)[105] = 0;
+  Ident(a)[5] = 0;
+}
+
+TEST(AddressSanitizer, DISABLED_DemoTooMuchMemoryTest) {
+  const size_t kAllocSize = (1 << 28) - 1024;
+  size_t total_size = 0;
+  while (true) {
+    char *x = (char*)malloc(kAllocSize);
+    memset(x, 0, kAllocSize);
+    total_size += kAllocSize;
+    fprintf(stderr, "total: %ldM\n", (long)total_size >> 20);
+  }
+}
+
+#ifdef __APPLE__
+#include "asan_mac_test.h"
+// TODO(glider): figure out whether we still need these tests. Is it correct
+// to intercept CFAllocator?
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorDefaultDoubleFree) {
+  EXPECT_DEATH(
+      CFAllocatorDefaultDoubleFree(),
+      "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {
+  EXPECT_DEATH(
+      CFAllocatorSystemDefaultDoubleFree(),
+      "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocDoubleFree) {
+  EXPECT_DEATH(CFAllocatorMallocDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_CFAllocatorMallocZoneDoubleFree) {
+  EXPECT_DEATH(CFAllocatorMallocZoneDoubleFree(), "attempting double-free");
+}
+
+TEST(AddressSanitizerMac, DISABLED_GCDDispatchAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchAsync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, DISABLED_GCDDispatchSync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchSync(), "Shadow byte and word");
+}
+
+
+TEST(AddressSanitizerMac, DISABLED_GCDReuseWqthreadsAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDReuseWqthreadsAsync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, DISABLED_GCDReuseWqthreadsSync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDReuseWqthreadsSync(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, DISABLED_GCDDispatchAfter) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDDispatchAfter(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, DISABLED_GCDSourceEvent) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDSourceEvent(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, DISABLED_GCDSourceCancel) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDSourceCancel(), "Shadow byte and word");
+}
+
+TEST(AddressSanitizerMac, DISABLED_GCDGroupAsync) {
+  // Make sure the whole ASan report is printed, i.e. that we don't die
+  // on a CHECK.
+  EXPECT_DEATH(TestGCDGroupAsync(), "Shadow byte and word");
+}
+
+void *MallocIntrospectionLockWorker(void *_) {
+  const int kNumPointers = 100;
+  int i;
+  void *pointers[kNumPointers];
+  for (i = 0; i < kNumPointers; i++) {
+    pointers[i] = malloc(i + 1);
+  }
+  for (i = 0; i < kNumPointers; i++) {
+    free(pointers[i]);
+  }
+
+  return NULL;
+}
+
+void *MallocIntrospectionLockForker(void *_) {
+  pid_t result = fork();
+  if (result == -1) {
+    perror("fork");
+  }
+  assert(result != -1);
+  if (result == 0) {
+    // Call malloc in the child process to make sure we won't deadlock.
+    void *ptr = malloc(42);
+    free(ptr);
+    exit(0);
+  } else {
+    // Return in the parent process.
+    return NULL;
+  }
+}
+
+TEST(AddressSanitizerMac, MallocIntrospectionLock) {
+  // Incorrect implementation of force_lock and force_unlock in our malloc zone
+  // will cause forked processes to deadlock.
+  // TODO(glider): need to detect that none of the child processes deadlocked.
+  const int kNumWorkers = 5, kNumIterations = 100;
+  int i, iter;
+  for (iter = 0; iter < kNumIterations; iter++) {
+    pthread_t workers[kNumWorkers], forker;
+    for (i = 0; i < kNumWorkers; i++) {
+      pthread_create(&workers[i], 0, MallocIntrospectionLockWorker, 0);
+    }
+    pthread_create(&forker, 0, MallocIntrospectionLockForker, 0);
+    for (i = 0; i < kNumWorkers; i++) {
+      pthread_join(workers[i], 0);
+    }
+    pthread_join(forker, 0);
+  }
+}
+
+void *TSDAllocWorker(void *test_key) {
+  if (test_key) {
+    void *mem = malloc(10);
+    pthread_setspecific(*(pthread_key_t*)test_key, mem);
+  }
+  return NULL;
+}
+
+TEST(AddressSanitizerMac, DISABLED_TSDWorkqueueTest) {
+  pthread_t th;
+  pthread_key_t test_key;
+  pthread_key_create(&test_key, CallFreeOnWorkqueue);
+  pthread_create(&th, NULL, TSDAllocWorker, &test_key);
+  pthread_join(th, NULL);
+  pthread_key_delete(test_key);
+}
+#endif  // __APPLE__
+
+int main(int argc, char **argv) {
+  progname = argv[0];
+  testing::GTEST_FLAG(death_test_style) = "threadsafe";
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}

Added: compiler-rt/trunk/lib/asan/tests/asan_test.ignore
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_test.ignore?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_test.ignore (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_test.ignore Tue Nov 29 19:07:02 2011
@@ -0,0 +1,2 @@
+fun:*IgnoreTest*
+fun:*SomeOtherFunc*

Added: compiler-rt/trunk/lib/asan/tests/asan_test_config.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_test_config.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_test_config.h (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_test_config.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,44 @@
+//===-- asan_test_config.h ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#ifndef ASAN_TEST_CONFIG_H
+#define ASAN_TEST_CONFIG_H
+
+#include <vector>
+#include <string>
+#include <map>
+
+#include "gtest/gtest.h"
+
+using std::string;
+using std::vector;
+using std::map;
+
+#ifndef ASAN_UAR
+# error "please define ASAN_UAR"
+#endif
+
+#ifndef ASAN_HAS_EXCEPTIONS
+# error "please define ASAN_HAS_EXCEPTIONS"
+#endif
+
+#ifndef ASAN_HAS_BLACKLIST
+# error "please define ASAN_HAS_BLACKLIST"
+#endif
+
+#ifndef ASAN_NEEDS_SEGV
+# error "please define ASAN_NEEDS_SEGV"
+#endif
+
+#define ASAN_PCRE_DOTALL ""
+
+#endif  // ASAN_TEST_CONFIG_H

Added: compiler-rt/trunk/lib/asan/tests/asan_test_utils.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/asan_test_utils.h?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/asan_test_utils.h (added)
+++ compiler-rt/trunk/lib/asan/tests/asan_test_utils.h Tue Nov 29 19:07:02 2011
@@ -0,0 +1,30 @@
+//===-- asan_test_utils.h ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ASAN_TEST_UTILS_H
+#define ASAN_TEST_UTILS_H
+
+// Make the compiler think that something is going on there.
+extern "C" void break_optimization(void *);
+
+// This function returns its parameter but in such a way that compiler
+// can not prove it.
+template<class T>
+__attribute__((noinline))
+static T Ident(T t) {
+  T ret = t;
+  break_optimization(&ret);
+  return ret;
+}
+
+#endif  // ASAN_TEST_UTILS_H

Added: compiler-rt/trunk/lib/asan/tests/global-overflow.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/global-overflow.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/global-overflow.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/global-overflow.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,12 @@
+#include <string.h>
+int main(int argc, char **argv) {
+  static char XXX[10];
+  static char YYY[10];
+  static char ZZZ[10];
+  memset(XXX, 0, 10);
+  memset(YYY, 0, 10);
+  memset(ZZZ, 0, 10);
+  int res = YYY[argc * 10];  // BOOOM
+  res += XXX[argc] + ZZZ[argc];
+  return res;
+}

Added: compiler-rt/trunk/lib/asan/tests/global-overflow.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/global-overflow.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/global-overflow.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/global-overflow.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,3 @@
+READ of size 1 at 0x.* thread T0
+    #0 0x.* in main .*global-overflow.cc:9
+0x.* is located 0 bytes to the right of global variable .*YYY.* of size 10

Added: compiler-rt/trunk/lib/asan/tests/heap-overflow.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/heap-overflow.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/heap-overflow.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/heap-overflow.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+  char *x = (char*)malloc(10 * sizeof(char));
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  free(x);
+  return res;
+}

Added: compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,6 @@
+READ of size 1 at 0x.* thread T0
+    #0 0x.* in main .*heap-overflow.cc:6
+0x.* is located 0 bytes to the right of 10-byte region
+allocated by thread T0 here:
+    #0 0x.* in malloc _asan_rtl_
+    #1 0x.* in main .*heap-overflow.cc:[45]

Added: compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl.Darwin
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl.Darwin?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl.Darwin (added)
+++ compiler-rt/trunk/lib/asan/tests/heap-overflow.tmpl.Darwin Tue Nov 29 19:07:02 2011
@@ -0,0 +1,8 @@
+READ of size 1 at 0x.* thread T0
+    #0 0x.* in main .*heap-overflow.cc:6
+0x.* is located 0 bytes to the right of 10-byte region
+allocated by thread T0 here:
+    #0 0x.* in .*mz_malloc.* _asan_rtl_
+    #1 0x.* in malloc_zone_malloc.*
+    #2 0x.* in malloc.*
+    #3 0x.* in main heap-overflow.cc:4

Added: compiler-rt/trunk/lib/asan/tests/large_func_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/large_func_test.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/large_func_test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/large_func_test.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+__attribute__((noinline))
+static void LargeFunction(int *x, int zero) {
+  x[0]++;
+  x[1]++;
+  x[2]++;
+  x[3]++;
+  x[4]++;
+  x[5]++;
+  x[6]++;
+  x[7]++;
+  x[8]++;
+  x[9]++;
+
+  x[zero + 111]++;  // we should report this exact line
+
+  x[10]++;
+  x[11]++;
+  x[12]++;
+  x[13]++;
+  x[14]++;
+  x[15]++;
+  x[16]++;
+  x[17]++;
+  x[18]++;
+  x[19]++;
+}
+
+int main(int argc, char **argv) {
+  int *x = new int[100];
+  LargeFunction(x, argc - 1);
+  delete x;
+}

Added: compiler-rt/trunk/lib/asan/tests/large_func_test.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/large_func_test.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/large_func_test.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/large_func_test.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,8 @@
+.*ERROR: AddressSanitizer heap-buffer-overflow on address 0x.* at pc 0x.* bp 0x.* sp 0x.*
+READ of size 4 at 0x.* thread T0
+    #0 0x.* in LargeFunction .*large_func_test.cc:15
+    #1 0x.* in main .*large_func_test.cc:3[012]
+0x.* is located 44 bytes to the right of 400-byte region
+allocated by thread T0 here:
+    #0 0x.* in operator new.*
+    #1 0x.* in main .*large_func_test.cc:30

Added: compiler-rt/trunk/lib/asan/tests/match_output.py
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/match_output.py?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/match_output.py (added)
+++ compiler-rt/trunk/lib/asan/tests/match_output.py Tue Nov 29 19:07:02 2011
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+
+import re
+import sys
+
+def matchFile(f, f_re):
+  for line_re in f_re:
+    line_re = line_re.rstrip()
+    if not line_re:
+      continue
+    if line_re[0] == '#':
+      continue
+    match = False
+    for line in f:
+      line = line.rstrip()
+      # print line
+      if re.search(line_re, line):
+        match = True
+        #print 'match: %s =~ %s' % (line, line_re)
+        break
+    if not match:
+      print 'no match for: %s' % (line_re)
+      return False
+  return True
+
+if len(sys.argv) != 2:
+  print >>sys.stderr, 'Usage: %s <template file>'
+  sys.exit(1)
+
+f = sys.stdin
+f_re = open(sys.argv[1])
+
+if not matchFile(f, f_re):
+  print >>sys.stderr, 'File does not match the template'
+  sys.exit(1)

Propchange: compiler-rt/trunk/lib/asan/tests/match_output.py
------------------------------------------------------------------------------
    svn:executable = *

Added: compiler-rt/trunk/lib/asan/tests/null_deref.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/null_deref.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/null_deref.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/null_deref.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,7 @@
+__attribute__((noinline))
+static void NullDeref(int *ptr) {
+  ptr[10]++;
+}
+int main() {
+  NullDeref((int*)0);
+}

Added: compiler-rt/trunk/lib/asan/tests/null_deref.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/null_deref.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/null_deref.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/null_deref.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,4 @@
+.*ERROR: AddressSanitizer crashed on unknown address 0x0*00028 .*pc 0x.*
+AddressSanitizer can not provide additional info. ABORTING
+    #0 0x.* in NullDeref.*null_deref.cc:3
+    #1 0x.* in main.*null_deref.cc:[67]

Added: compiler-rt/trunk/lib/asan/tests/shared-lib-test-so.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/shared-lib-test-so.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/shared-lib-test-so.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/shared-lib-test-so.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,21 @@
+//===-- asan_rtl.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <stdio.h>
+
+int pad[10];
+int GLOB[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+extern "C"
+void inc(int index) {
+  GLOB[index]++;
+}

Added: compiler-rt/trunk/lib/asan/tests/shared-lib-test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/shared-lib-test.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/shared-lib-test.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/shared-lib-test.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,44 @@
+//===-- asan_rtl.cc ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+//===----------------------------------------------------------------------===//
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+using std::string;
+
+const char kMyName[] = "shared-lib-test";
+const char kSoName[] = "shared-lib-test-so";
+
+typedef void (fun_t)(int x);
+
+int main(int argc, char *argv[]) {
+  string path = strdup(argv[0]);
+  size_t start = path.find(kMyName);
+  if (start == string::npos) return 1;
+  path.replace(start, strlen(kMyName), kSoName);
+  path += ".so";
+  // printf("opening %s ... ", path.c_str());
+  void *lib = dlopen(path.c_str(), RTLD_NOW);
+  if (!lib) {
+    printf("error in dlopen(): %s\n", dlerror());
+    return 1;
+  }
+  fun_t *inc = (fun_t*)dlsym(lib, "inc");
+  if (!inc) return 1;
+  // printf("ok\n");
+  inc(1);
+  inc(-1);
+  return 0;
+}

Added: compiler-rt/trunk/lib/asan/tests/shared-lib-test.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/shared-lib-test.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/shared-lib-test.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/shared-lib-test.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,7 @@
+#.*ERROR: AddressSanitizer global-buffer-overflow on address 0x.* at pc 0x.* bp 0x.* sp 0x.*
+#READ of size 4 at 0x.* thread T0
+#    #0 0x.* in inc .*shared-lib-test-so.cc:11
+#    #1 0x.* in main .*shared-lib-test.cc:33
+#    #2 0x.* in __libc_start_main.*
+#0x.* is located 4 bytes to the left of global variable 'GLOB' (.*) of size 40
+#0x.* is located 52 bytes to the right of global variable 'pad' (.*) of size 40

Added: compiler-rt/trunk/lib/asan/tests/stack-overflow.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/stack-overflow.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/stack-overflow.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/stack-overflow.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,7 @@
+#include <string.h>
+int main(int argc, char **argv) {
+  char x[10];
+  memset(x, 0, 10);
+  int res = x[argc * 10];  // BOOOM
+  return res;
+}

Added: compiler-rt/trunk/lib/asan/tests/stack-overflow.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/stack-overflow.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/stack-overflow.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/stack-overflow.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,3 @@
+READ of size 1 at 0x.* thread T0
+    #0 0x.* in main .*stack-overflow.cc:5
+Address 0x.* is .* frame <main>

Added: compiler-rt/trunk/lib/asan/tests/stack-use-after-return.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/stack-use-after-return.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/stack-use-after-return.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/stack-use-after-return.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+__attribute__((noinline))
+char *Ident(char *x) {
+  fprintf(stderr, "1: %p\n", x);
+  return x;
+}
+
+__attribute__((noinline))
+char *Func1() {
+  char local;
+  return Ident(&local);
+}
+
+__attribute__((noinline))
+void Func2(char *x) {
+  fprintf(stderr, "2: %p\n", x);
+  *x = 1;
+}
+
+int main(int argc, char **argv) {
+  Func2(Func1());
+  return 0;
+}

Added: compiler-rt/trunk/lib/asan/tests/stack-use-after-return.disabled
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/stack-use-after-return.disabled?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/stack-use-after-return.disabled (added)
+++ compiler-rt/trunk/lib/asan/tests/stack-use-after-return.disabled Tue Nov 29 19:07:02 2011
@@ -0,0 +1,3 @@
+WRITE of size 1 .* thread T0
+#0.*Func2.*stack-use-after-return.cc:18
+is located in frame <.*Func1.*> of T0's stack

Added: compiler-rt/trunk/lib/asan/tests/strncpy-overflow.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/strncpy-overflow.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/strncpy-overflow.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/strncpy-overflow.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,9 @@
+#include <string.h>
+#include <stdlib.h>
+int main(int argc, char **argv) {
+  char *hello = (char*)malloc(6);
+  strcpy(hello, "hello");
+  char *short_buffer = (char*)malloc(9);
+  strncpy(short_buffer, hello, 10);  // BOOM
+  return short_buffer[8];
+}

Added: compiler-rt/trunk/lib/asan/tests/strncpy-overflow.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/strncpy-overflow.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/strncpy-overflow.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/strncpy-overflow.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,7 @@
+WRITE of size 1 at 0x.* thread T0
+    #0 0x.* in strncpy _asan_rtl_
+    #1 0x.* in main .*strncpy-overflow.cc:[78]
+0x.* is located 0 bytes to the right of 9-byte region
+allocated by thread T0 here:
+    #0 0x.* in malloc _asan_rtl_
+    #1 0x.* in main .*strncpy-overflow.cc:6

Added: compiler-rt/trunk/lib/asan/tests/test_output.sh
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/test_output.sh?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/test_output.sh (added)
+++ compiler-rt/trunk/lib/asan/tests/test_output.sh Tue Nov 29 19:07:02 2011
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+OS=`uname`
+CXX=$1
+CXXFLAGS="-mno-omit-leaf-frame-pointer"
+SYMBOLIZER=../scripts/asan_symbolize.py
+
+for t in  *.tmpl; do
+  for b in 32 64; do
+    for O in 1 2 3; do
+      # TODO: reinstate -O0, if that's really needed.
+      c=`basename $t .tmpl`
+      c_so=$c-so
+      exe=$c.$b.O$O
+      so=$c_so.$b.O$O.so
+      $CXX $CXXFLAGS -g -m$b -faddress-sanitizer -O$O $c.cc -o $exe
+      [ -e "$c_so.cc" ] && $CXX $CXXFLAGS -g -m$b -faddress-sanitizer -O$O $c_so.cc -fPIC -shared -o $so
+      # If there's an OS-specific template, use it.
+      # Please minimize the use of OS-specific templates.
+      if [ -e "$t.$OS" ]
+      then
+        actual_t="$t.$OS"
+      else
+        actual_t="$t"
+      fi
+      ./$exe 2>&1 | $SYMBOLIZER 2> /dev/null | c++filt | ./match_output.py $actual_t || exit 1
+      echo $exe
+      rm ./$exe
+      [ -e "$so" ] && rm ./$so
+    done
+  done
+done
+exit 0

Propchange: compiler-rt/trunk/lib/asan/tests/test_output.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: compiler-rt/trunk/lib/asan/tests/use-after-free.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/use-after-free.c?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/use-after-free.c (added)
+++ compiler-rt/trunk/lib/asan/tests/use-after-free.c Tue Nov 29 19:07:02 2011
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}

Added: compiler-rt/trunk/lib/asan/tests/use-after-free.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/use-after-free.cc?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/use-after-free.cc (added)
+++ compiler-rt/trunk/lib/asan/tests/use-after-free.cc Tue Nov 29 19:07:02 2011
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+int main() {
+  char *x = (char*)malloc(10 * sizeof(char));
+  free(x);
+  return x[5];
+}

Added: compiler-rt/trunk/lib/asan/tests/use-after-free.tmpl
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/tests/use-after-free.tmpl?rev=145463&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/tests/use-after-free.tmpl (added)
+++ compiler-rt/trunk/lib/asan/tests/use-after-free.tmpl Tue Nov 29 19:07:02 2011
@@ -0,0 +1,10 @@
+.*ERROR: AddressSanitizer heap-use-after-free on address 0x.* at pc 0x.* bp 0x.* sp 0x.*
+READ of size 1 at 0x.* thread T0
+    #0 0x.* in main .*use-after-free.cc:5
+0x.* is located 5 bytes inside of 10-byte region .0x.*,0x.*
+freed by thread T0 here:
+    #0 0x.* in free _asan_rtl_
+    #1 0x.* in main .*use-after-free.cc:[45]
+previously allocated by thread T0 here:
+    #0 0x.* in malloc _asan_rtl_
+    #1 0x.* in main .*use-after-free.cc:3





More information about the llvm-commits mailing list