From 91971721b75fcd6c83a36a72b0a8d7bb3ec1e91e Mon Sep 17 00:00:00 2001 From: Slava Barinov Date: Thu, 3 Aug 2017 16:14:59 +0300 Subject: [PATCH 01/16] [TTC-5] Forbid section anchors for ASan build (PR sanitizer/81697) gcc/ * varasm.c (use_object_blocks_p): Forbid section anchors for ASan gcc/testsuite/ * g++.dg/asan/global-alignment.C: New test to test global variables alignment. Change-Id: I3887e356397c599ec74793de6d60bc285a2c872b Signed-off-by: Slava Barinov --- gcc/testsuite/g++.dg/asan/global-alignment.C | 17 +++++++++++++++++ gcc/varasm.c | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/asan/global-alignment.C diff --git a/gcc/testsuite/g++.dg/asan/global-alignment.C b/gcc/testsuite/g++.dg/asan/global-alignment.C new file mode 100644 index 0000000..c011c70 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/global-alignment.C @@ -0,0 +1,17 @@ +/* { dg-options "-fmerge-all-constants" } */ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ + +#include +#include + +const char kRecoveryInstallString[] = "NEW"; +const char kRecoveryUpdateString[] = "UPDATE"; +const char kRecoveryUninstallationString[] = "UNINSTALL"; + +const std::map kStringToRequestMap = { + {kRecoveryInstallString, 0}, + {kRecoveryUpdateString, 0}, + {kRecoveryUninstallationString, 0}, +}; +/* { dg-final { scan-assembler-times {\.section\s+\.rodata\n(?:(?!\.section).)*\.(string|ascii|asciz)\s+"NEW} 1 } } */ diff --git a/gcc/varasm.c b/gcc/varasm.c index da88f5b..3220675 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -344,7 +344,8 @@ get_section (const char *name, unsigned int flags, tree decl) static bool use_object_blocks_p (void) { - return flag_section_anchors; + return (flag_section_anchors + && !(flag_sanitize & SANITIZE_ADDRESS)); } /* Return the object_block structure for section SECT. Create a new -- 2.7.4 From bdfd925eda6c0c5857fe9282e973516ac8bedb9f Mon Sep 17 00:00:00 2001 From: Denis Khalikov Date: Fri, 18 Aug 2017 18:07:28 +0300 Subject: [PATCH 02/16] [TTC-6] packaging: Support for gcc-contrib. This patch deletes all scripts from gcc *spec files. All scripts moved to gcc-contrib package. Change-Id: I847a5c61b69cc74aadf59c31e3b04a404a4d13b0 --- packaging/ASAN_OPTIONS | 1 - packaging/LSAN_OPTIONS | 1 - packaging/UBSAN_OPTIONS | 1 - packaging/asan_symbolize.py | 720 ------------------------------------------ packaging/extract-ubsan-logs | 17 - packaging/gcc-aarch64.spec | 279 ---------------- packaging/gcc-armv7l.spec | 279 ---------------- packaging/gcc-force-options | 129 -------- packaging/gcc-unforce-options | 19 -- packaging/linaro-gcc.spec | 279 ---------------- packaging/lsan.supp | 1 - packaging/macros.ubsan | 39 --- 12 files changed, 1765 deletions(-) delete mode 100644 packaging/ASAN_OPTIONS delete mode 100644 packaging/LSAN_OPTIONS delete mode 100644 packaging/UBSAN_OPTIONS delete mode 100755 packaging/asan_symbolize.py delete mode 100644 packaging/extract-ubsan-logs delete mode 100644 packaging/gcc-force-options delete mode 100644 packaging/gcc-unforce-options delete mode 100644 packaging/lsan.supp delete mode 100644 packaging/macros.ubsan diff --git a/packaging/ASAN_OPTIONS b/packaging/ASAN_OPTIONS deleted file mode 100644 index 50d644e..0000000 --- a/packaging/ASAN_OPTIONS +++ /dev/null @@ -1 +0,0 @@ -halt_on_error=false:start_deactivated=true:print_cmdline=true:quarantine_size_mb=1:detect_leaks=0:full_address_space=true diff --git a/packaging/LSAN_OPTIONS b/packaging/LSAN_OPTIONS deleted file mode 100644 index db30ebc..0000000 --- a/packaging/LSAN_OPTIONS +++ /dev/null @@ -1 +0,0 @@ -print_cmdline=true:detect_leaks=1:log_path=/tmp/lsan.log:log_exe_name=1:fast_unwind_on_malloc=false:malloc_context_size=5:suppressions=/lsan.supp:print_suppressions=false diff --git a/packaging/UBSAN_OPTIONS b/packaging/UBSAN_OPTIONS deleted file mode 100644 index 0fbf7a7..0000000 --- a/packaging/UBSAN_OPTIONS +++ /dev/null @@ -1 +0,0 @@ -print_cmdline=true:log_path=/tmp/ubsan.log \ No newline at end of file diff --git a/packaging/asan_symbolize.py b/packaging/asan_symbolize.py deleted file mode 100755 index f37530b..0000000 --- a/packaging/asan_symbolize.py +++ /dev/null @@ -1,720 +0,0 @@ -#!/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 https://github.com/llvm-mirror/compiler-rt/blob/master/LICENSE.TXT -# for details. -# -#===------------------------------------------------------------------------===# -import argparse -import array -import binascii -import bisect -import os -import re -import subprocess -import sys - -symbolizers = {} -DEBUG = False -demangle = False -binutils_prefix = None -sysroot_path = None -binary_name_filter = None -fix_filename_patterns = None -logfile = sys.stdin -separate_debug_dir_list = [] -prelink_offset = None - -# FIXME: merge the code that calls fix_filename(). -def fix_filename(file_name): - if fix_filename_patterns: - for path_to_cut in fix_filename_patterns: - 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) - return file_name - -def sysroot_path_filter(binary_name): - return sysroot_path + binary_name - -def use_binutils_prefix(tool_name): - if binutils_prefix: - tool_name = binutils_prefix + tool_name - return tool_name - -def print_error_message(message): - print >> sys.stderr, 'Error occured during symbolizisation: ' + message - -class DebugInfoHandler(object): - def __init__(self, binary_name_filter=None): - self.binary_name_filter = binary_name_filter - self.global_debug_dir_list = [ self.use_name_filter("/usr/lib/debug") ] - if separate_debug_dir_list: - self.global_debug_dir_list = separate_debug_dir_list - - def use_name_filter(self, binary_name): - if self.binary_name_filter: - binary_name = self.binary_name_filter(binary_name) - return binary_name - - def calc_crc32(self, filename): - buf = open(filename,'rb').read() - buf = (binascii.crc32(buf, 0) & 0xFFFFFFFF) - return "%08X" % buf - - def readelf_binary(self, options, binary): - cmd = [use_binutils_prefix('readelf'), options,'-W', binary] - try: - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=open(os.devnull, 'w')) - except: - print_error_message('the following command failed:\n''"' + ' '.join(cmd) + '"') - return - (readelf_out, _) = process.communicate() - if process.returncode == 0: - return readelf_out - - def has_debuginfo(self, binary): - readelf_out = self.readelf_binary('-S', binary) - return readelf_out and (".debug_" in readelf_out) - - def get_buildid(self, binary): - readelf_out = self.readelf_binary('-nw', binary) - ''' - Build ID is 40-length hex value following after "Build ID:". - e.g.: - Notes at offset 0x00000274 with length 0x00000024: - Owner Data size Description - GNU 0x00000014 NT_GNU_BUILD_ID (unique build ID bitstring) - Build ID: 977b1d1375ba6791d5f6dd38d8d55b95f9fca33a - ''' - if readelf_out: - readelf_lines = readelf_out.split("\n"); - buildid_lines = filter(re.compile('Build ID:').search, readelf_lines) - for line in buildid_lines: - match = re.search('[a-f0-9]{40}', line) - if match: - return match.group(0) - else: - print_error_message('failed to read Build ID value from ' + binary) - - def get_debuglink_name(self, binary): - readelf_out = self.readelf_binary('--string-dump=.gnu_debuglink', binary) - ''' - "debug link" is the last word in the first line of dump. - e.g.: - String dump of section '.gnu_debuglink': - [ 0] HeapOutOfBounds.out.debug - ''' - if readelf_out: - readelf_lines = filter(None, readelf_out.split("\n")); - headline ="String dump of section '.gnu_debuglink':" - try: - debuglink_line_idx = readelf_lines.index(headline) + 1 - except ValueError: - # There is no gnu_debuglink section in this binary - return - if len(readelf_lines) > debuglink_line_idx: - return readelf_lines[debuglink_line_idx].split()[-1] - else: - print_error_message('failed to read debuglink value from ' + binary) - - def get_debuglink_crc(self, binary): - readelf_out = self.readelf_binary('--hex-dump=.gnu_debuglink', binary) - ''' - crc is the last hex group (before string representation) in the last line of dump. - e.g. (crc is f89f21c2) : - Hex dump of section '.gnu_debuglink': - 0x00000000 48656170 4f75744f 66426f75 6e64732e HeapOutOfBounds. - 0x00000010 6f75742e 64656275 67000000 f89f21c2 out.debug.....!. - ''' - if readelf_out: - # get last non-empty line - crc_line = filter(None, readelf_out.split("\n"))[-1] - # remove last 16 characters (string dump) from line - crc_line = crc_line[:-16] - # crc is last word in string - crc = crc_line.split()[-1] - match = re.match('[a-f0-9]{8}', crc) - if match: - if sys.byteorder == 'little': - crc = array.array('i', binascii.unhexlify(crc) ) - crc.byteswap() - crc = binascii.hexlify(crc) - return crc - else: - print_error_message('failed to get crc checksum from debuglink in ' + binary) - - - def is_prelinked(self, binary): - readelf_out = self.readelf_binary('-S', binary) - return readelf_out and ".gnu.prelink_undo" in readelf_out - - def get_load_address(self, binary): - readelf_out = self.readelf_binary('-l', binary) - ''' - Readelf program headers output example: - Elf file type is DYN (Shared object file) - Entry point 0xb1160668 - There are 10 program headers, starting at offset 52 - Program Headers: - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - EXIDX 0x124754 0xb126c754 0xb126c754 0x04498 0x04498 R 0x4 - [...] - LOAD 0x000000 0xb1148000 0xb1148000 0x12be9c 0x12be9c R E 0x8000 - - ''' - readelf_lines = readelf_out.split("\n"); - load_lines = filter(re.compile( - '[\s]*LOAD[\s]+0x[0]+[\s]+0x[a-fA-f\d]+').match, readelf_lines) - if load_lines: - return load_lines[0].split()[2] - else: - print_error_message('failed to get load address in ' + binary) - - def get_prelink_offset(self, orig, prelinked): - if not self.is_prelinked(prelinked): - return - orig_load_addr = self.get_load_address(orig) - prelinked_load_addr = self.get_load_address(prelinked) - return int(prelinked_load_addr, 16) - int(orig_load_addr, 16) - - def locate_in_orig_dir(self, debuglink_name, orig_binary_name): - debuginfo = os.path.join(os.path.dirname(orig_binary_name), debuglink_name) - debuginfo = self.use_name_filter(debuginfo) - return [debuginfo] - - def locate_in_debug_subdir(self, debuglink_name, orig_binary_name): - debuginfo = os.path.join(os.path.dirname(orig_binary_name), '.debug', debuglink_name) - debuginfo = self.use_name_filter(debuginfo) - return [debuginfo] - - def locate_in_global_debug_dir(self, debuglink_name, orig_binary_name): - debuginfo_list = [] - for global_debug_dir in self.global_debug_dir_list: - debuginfo = global_debug_dir + os.path.join(os.path.dirname(orig_binary_name), debuglink_name) - debuginfo_list.append(debuginfo) - return debuginfo_list - - def locate_in_buildid_dir(self, debuglink_name, orig_binary_name): - dir_name = debuglink_name[0:2] - file_name = debuglink_name[2:] + ".debug" - debuginfo_list = [] - for global_debug_dir in self.global_debug_dir_list: - debuginfo = os.path.join(global_debug_dir, ".build-id", dir_name, file_name) - debuginfo_list.append(debuginfo) - return debuginfo_list - - def get_debuginfo(self,binary_name): - global prelink_offset - prelink_offset = None - orig_binary_name = binary_name - # First apply sysroot path if defined to get real binary - real_binary = self.use_name_filter(binary_name) - if self.has_debuginfo(real_binary): - return real_binary - # Look for debuginfo file according to GDB rules - # 1) "build-id" method - buildid_name = self.get_buildid(real_binary) - debugfile_list = [] - if buildid_name: - debugfile_list = self.locate_in_buildid_dir(buildid_name, orig_binary_name) - for debugfile in debugfile_list: - if os.path.isfile(debugfile): - prelink_offset = self.get_prelink_offset(debugfile, real_binary) - return debugfile - # 2) "debug link" method - debuglink_name = self.get_debuglink_name(real_binary) - debuglink_crc = self.get_debuglink_crc(real_binary) - debugfile_list = [] - if debuglink_name and debuglink_crc: - debuglink_locate_list = [ - self.locate_in_orig_dir, - self.locate_in_debug_subdir, - self.locate_in_global_debug_dir ] - for debuglink_locate_function in debuglink_locate_list: - debugfile_list = debuglink_locate_function(debuglink_name, orig_binary_name) - for debugfile in debugfile_list: - if os.path.isfile(debugfile): - debugfile_crc = self.calc_crc32(debugfile) - if int(debuglink_crc,16) == int(debugfile_crc, 16): - prelink_offset = self.get_prelink_offset(debugfile, real_binary) - return debugfile - return real_binary - -def guess_arch(addr): - # Guess which arch we're running. 10 = len('0x') + 8 hex digits. - if len(addr) > 10: - return 'x86_64' - else: - return 'i386' - -class Symbolizer(object): - def __init__(self): - pass - - def symbolize(self, addr, binary, offset): - """Symbolize the given address (pair of binary and offset). - - Overriden in subclasses. - Args: - addr: virtual address of an instruction. - binary: path to executable/shared object containing this instruction. - offset: instruction offset in the @binary. - Returns: - list of strings (one string for each inlined frame) describing - the code locations for this instruction (that is, function name, file - name, line and column numbers). - """ - return None - - -class LLVMSymbolizer(Symbolizer): - def __init__(self, symbolizer_path, default_arch, system, dsym_hints=[]): - super(LLVMSymbolizer, self).__init__() - self.symbolizer_path = symbolizer_path - self.default_arch = default_arch - self.system = system - self.dsym_hints = dsym_hints - self.pipe = self.open_llvm_symbolizer() - - def open_llvm_symbolizer(self): - cmd = [self.symbolizer_path, - '--use-symbol-table=true', - '--demangle=%s' % demangle, - '--functions=short', - '--inlining=true', - '--default-arch=%s' % self.default_arch] - if self.system == 'Darwin': - for hint in self.dsym_hints: - cmd.append('--dsym-hint=%s' % hint) - if DEBUG: - print ' '.join(cmd) - try: - result = subprocess.Popen(cmd, stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - except OSError: - result = None - return result - - def symbolize(self, addr, binary, offset): - """Overrides Symbolizer.symbolize.""" - if not self.pipe: - return None - result = [] - try: - symbolizer_input = '"%s" %s' % (binary, offset) - if DEBUG: - print symbolizer_input - print >> self.pipe.stdin, symbolizer_input - while True: - function_name = self.pipe.stdout.readline().rstrip() - if not function_name: - break - file_name = self.pipe.stdout.readline().rstrip() - file_name = fix_filename(file_name) - if (not function_name.startswith('??') or - not file_name.startswith('??')): - # Append only non-trivial frames. - result.append('%s in %s %s' % (addr, function_name, - file_name)) - except Exception: - result = [] - if not result: - result = None - return result - - -def LLVMSymbolizerFactory(system, default_arch, dsym_hints=[]): - symbolizer_path = os.getenv('LLVM_SYMBOLIZER_PATH') - if not symbolizer_path: - symbolizer_path = os.getenv('ASAN_SYMBOLIZER_PATH') - if not symbolizer_path: - # Assume llvm-symbolizer is in PATH. - symbolizer_path = 'llvm-symbolizer' - return LLVMSymbolizer(symbolizer_path, default_arch, system, dsym_hints) - - -class Addr2LineSymbolizer(Symbolizer): - def __init__(self, binary): - super(Addr2LineSymbolizer, self).__init__() - self.binary = binary - - def symbolize(self, addr, binary, offset): - """Overrides Symbolizer.symbolize.""" - cmd = [use_binutils_prefix('addr2line'), '-fi'] - if demangle: - cmd += ['--demangle'] - cmd += ['-e', self.binary, offset] - if DEBUG: - print ' '.join(cmd) - self.pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE) - result = [] - if self.binary != binary: - return None - try: - lines = self.pipe.stdout.readlines() - except Exception: - lines = [] - if not lines: - lines.append('??') - lines.append('??:?') - for i in range(0, len(lines), 2): - function_name = lines[i].rstrip() - file_name = fix_filename(lines[i+1].rstrip()) - result.append('%s in %s %s' % (addr, function_name, file_name)) - return result - - -class UnbufferedLineConverter(object): - """ - Wrap a child process that responds to each line of input with one line of - output. Uses pty to trick the child into providing unbuffered output. - """ - def __init__(self, args, close_stderr=False): - # Local imports so that the script can start on Windows. - import pty - import termios - pid, fd = pty.fork() - if pid == 0: - # We're the child. Transfer control to command. - if close_stderr: - dev_null = os.open('/dev/null', 0) - os.dup2(dev_null, 2) - os.execvp(args[0], args) - else: - # Disable echoing. - attr = termios.tcgetattr(fd) - attr[3] = attr[3] & ~termios.ECHO - termios.tcsetattr(fd, termios.TCSANOW, attr) - # Set up a file()-like interface to the child process - self.r = os.fdopen(fd, "r", 1) - self.w = os.fdopen(os.dup(fd), "w", 1) - - def convert(self, line): - self.w.write(line + "\n") - return self.readline() - - def readline(self): - return self.r.readline().rstrip() - - -class DarwinSymbolizer(Symbolizer): - def __init__(self, addr, binary): - super(DarwinSymbolizer, self).__init__() - self.binary = binary - self.arch = guess_arch(addr) - self.open_atos() - - def open_atos(self): - if DEBUG: - print 'atos -o %s -arch %s' % (self.binary, self.arch) - cmdline = ['atos', '-o', self.binary, '-arch', self.arch] - self.atos = UnbufferedLineConverter(cmdline, close_stderr=True) - - def symbolize(self, addr, binary, offset): - """Overrides Symbolizer.symbolize.""" - if self.binary != binary: - return None - atos_line = self.atos.convert('0x%x' % int(offset, 16)) - while "got symbolicator for" in atos_line: - atos_line = self.atos.readline() - # A well-formed atos response looks like this: - # foo(type1, type2) (in object.name) (filename.cc:80) - match = re.match('^(.*) \(in (.*)\) \((.*:\d*)\)$', atos_line) - if DEBUG: - print 'atos_line: ', atos_line - if match: - function_name = match.group(1) - function_name = re.sub('\(.*?\)', '', function_name) - file_name = fix_filename(match.group(3)) - return ['%s in %s %s' % (addr, function_name, file_name)] - else: - return ['%s in %s' % (addr, atos_line)] - - -# Chain several symbolizers so that if one symbolizer fails, we fall back -# to the next symbolizer in chain. -class ChainSymbolizer(Symbolizer): - def __init__(self, symbolizer_list): - super(ChainSymbolizer, self).__init__() - self.symbolizer_list = symbolizer_list - - def symbolize(self, addr, binary, offset): - """Overrides Symbolizer.symbolize.""" - for symbolizer in self.symbolizer_list: - if symbolizer: - result = symbolizer.symbolize(addr, binary, offset) - if result: - return result - return None - - def append_symbolizer(self, symbolizer): - self.symbolizer_list.append(symbolizer) - - -def BreakpadSymbolizerFactory(binary): - suffix = os.getenv('BREAKPAD_SUFFIX') - if suffix: - filename = binary + suffix - if os.access(filename, os.F_OK): - return BreakpadSymbolizer(filename) - return None - - -def SystemSymbolizerFactory(system, addr, binary): - if system == 'Darwin': - return DarwinSymbolizer(addr, binary) - elif system == 'Linux': - return Addr2LineSymbolizer(binary) - - -class BreakpadSymbolizer(Symbolizer): - def __init__(self, filename): - super(BreakpadSymbolizer, self).__init__() - self.filename = filename - lines = file(filename).readlines() - self.files = [] - self.symbols = {} - self.address_list = [] - self.addresses = {} - # MODULE mac x86_64 A7001116478B33F18FF9BEDE9F615F190 t - fragments = lines[0].rstrip().split() - self.arch = fragments[2] - self.debug_id = fragments[3] - self.binary = ' '.join(fragments[4:]) - self.parse_lines(lines[1:]) - - def parse_lines(self, lines): - cur_function_addr = '' - for line in lines: - fragments = line.split() - if fragments[0] == 'FILE': - assert int(fragments[1]) == len(self.files) - self.files.append(' '.join(fragments[2:])) - elif fragments[0] == 'PUBLIC': - self.symbols[int(fragments[1], 16)] = ' '.join(fragments[3:]) - elif fragments[0] in ['CFI', 'STACK']: - pass - elif fragments[0] == 'FUNC': - cur_function_addr = int(fragments[1], 16) - if not cur_function_addr in self.symbols.keys(): - self.symbols[cur_function_addr] = ' '.join(fragments[4:]) - else: - # Line starting with an address. - addr = int(fragments[0], 16) - self.address_list.append(addr) - # Tuple of symbol address, size, line, file number. - self.addresses[addr] = (cur_function_addr, - int(fragments[1], 16), - int(fragments[2]), - int(fragments[3])) - self.address_list.sort() - - def get_sym_file_line(self, addr): - key = None - if addr in self.addresses.keys(): - key = addr - else: - index = bisect.bisect_left(self.address_list, addr) - if index == 0: - return None - else: - key = self.address_list[index - 1] - sym_id, size, line_no, file_no = self.addresses[key] - symbol = self.symbols[sym_id] - filename = self.files[file_no] - if addr < key + size: - return symbol, filename, line_no - else: - return None - - def symbolize(self, addr, binary, offset): - if self.binary != binary: - return None - res = self.get_sym_file_line(int(offset, 16)) - if res: - function_name, file_name, line_no = res - result = ['%s in %s %s:%d' % ( - addr, function_name, file_name, line_no)] - print result - return result - else: - return None - - -class SymbolizationLoop(object): - def __init__(self, binary_name_filter=None, dsym_hint_producer=None): - if sys.platform == 'win32': - # ASan on Windows uses dbghelp.dll to symbolize in-process, which works - # even in sandboxed processes. Nothing needs to be done here. - self.process_line = self.process_line_echo - else: - # Used by clients who may want to supply a different binary name. - # E.g. in Chrome several binaries may share a single .dSYM. - self.binary_name_filter = binary_name_filter - self.dsym_hint_producer = dsym_hint_producer - self.system = os.uname()[0] - if self.system not in ['Linux', 'Darwin', 'FreeBSD']: - raise Exception('Unknown system') - self.llvm_symbolizers = {} - self.last_llvm_symbolizer = None - self.dsym_hints = set([]) - self.frame_no = 0 - self.process_line = self.process_line_posix - - def symbolize_address(self, addr, binary, offset): - # On non-Darwin (i.e. on platforms without .dSYM debug info) always use - # a single symbolizer binary. - # On Darwin, if the dsym hint producer is present: - # 1. check whether we've seen this binary already; if so, - # use |llvm_symbolizers[binary]|, which has already loaded the debug - # info for this binary (might not be the case for - # |last_llvm_symbolizer|); - # 2. otherwise check if we've seen all the hints for this binary already; - # if so, reuse |last_llvm_symbolizer| which has the full set of hints; - # 3. otherwise create a new symbolizer and pass all currently known - # .dSYM hints to it. - if not binary in self.llvm_symbolizers: - use_new_symbolizer = True - if self.system == 'Darwin' and self.dsym_hint_producer: - dsym_hints_for_binary = set(self.dsym_hint_producer(binary)) - use_new_symbolizer = bool(dsym_hints_for_binary - self.dsym_hints) - self.dsym_hints |= dsym_hints_for_binary - if self.last_llvm_symbolizer and not use_new_symbolizer: - self.llvm_symbolizers[binary] = self.last_llvm_symbolizer - else: - self.last_llvm_symbolizer = LLVMSymbolizerFactory( - self.system, guess_arch(addr), self.dsym_hints) - self.llvm_symbolizers[binary] = self.last_llvm_symbolizer - # Use the chain of symbolizers: - # Breakpad symbolizer -> LLVM symbolizer -> addr2line/atos - # (fall back to next symbolizer if the previous one fails). - if not binary in symbolizers: - symbolizers[binary] = ChainSymbolizer( - [BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]]) - result = symbolizers[binary].symbolize(addr, binary, offset) - if result is None: - # Initialize system symbolizer only if other symbolizers failed. - symbolizers[binary].append_symbolizer( - SystemSymbolizerFactory(self.system, addr, binary)) - result = symbolizers[binary].symbolize(addr, binary, offset) - # The system symbolizer must produce some result. - assert result - return result - - def get_symbolized_lines(self, symbolized_lines): - if not symbolized_lines: - return [self.current_line] - else: - result = [] - for symbolized_frame in symbolized_lines: - if '?' in symbolized_frame: - symbolized_frame += " " + re.search('\(.*?\)',self.current_line).group(0) - result.append(' #%s %s' % (str(self.frame_no), symbolized_frame.rstrip())) - self.frame_no += 1 - return result - - def process_logfile(self): - self.frame_no = 0 - for line in logfile: - processed = self.process_line(line) - print '\n'.join(processed) - - def process_line_echo(self, line): - return [line.rstrip()] - - def have_line_to_symbolize(self, line): - #0 0x7f6e35cf2e45 in func (/blah/foo.so+0x11fe45) - stack_trace_line_format = ( - '^( *#([0-9]+) *)(0x[0-9a-f]+)( *in [^/]+)? *\((.*)\+(0x[0-9a-f]+)\)') - match = re.match(stack_trace_line_format, line) - if not match: - # If already symbolized (format below) - fix given frame number - #0 0x7f6e35cf2e45 in func foo:46 - stack_trace_line_format_symbolized = ( - '^( *#([0-9]+) *)(0x[0-9a-f]+)( *in [^/]+)? *(.*)\:([0-9]+)') - match_symbolized = re.match(stack_trace_line_format_symbolized, line); - if match_symbolized: - # Frame number from line - match_frame_number = match_symbolized.group(2) - if (self.frame_no != int(match_frame_number)): - self.current_line = re.sub(match_frame_number, str(self.frame_no), line, count=1) - self.frame_no += 1 - return match - - def process_line_posix(self, line): - self.current_line = line.rstrip() - match = self.have_line_to_symbolize(line) - if not match: - return [self.current_line] - if DEBUG: - print line - _, frameno_str, addr, func, binary, offset = match.groups() - if frameno_str == '0': - # Assume that frame #0 is the first frame of new stack trace. - self.frame_no = 0 - original_binary = binary - if self.binary_name_filter: - binary = self.binary_name_filter(binary) - # Correct offset from backtrace if the binary was prelinked - # and printed address considers the prelink offset: - if prelink_offset: - real_offset = int(offset,16) - if real_offset > prelink_offset: - #FIXME: Need to check that offset fits section size - offset = hex(real_offset - prelink_offset) - if DEBUG: - print 'real address: ' + offset - symbolized_line = self.symbolize_address(addr, binary, offset) - if not symbolized_line: - if original_binary != binary: - symbolized_line = self.symbolize_address(addr, binary, offset) - return self.get_symbolized_lines(symbolized_line) - - -if __name__ == '__main__': - parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description='ASan symbolization script', - epilog='Example of use:\n' - 'asan_symbolize.py -c "$HOME/opt/cross/bin/armv7l-tizen-linux-gnueabi-" ' - '-s "$HOME/SymbolFiles" < asan.log') - parser.add_argument('path_to_cut', nargs='*', - help='pattern to be cut from the result file path ') - parser.add_argument('-d','--demangle', action='store_true', - help='demangle function names') - parser.add_argument('-s', metavar='SYSROOT', - help='set path to sysroot for sanitized binaries') - parser.add_argument('-c', metavar='CROSS_COMPILE', - help='set prefix for binutils') - parser.add_argument('-l','--logfile', default=sys.stdin, - type=argparse.FileType('r'), - help='set log file name to parse, default is stdin') - parser.add_argument('-y', '--debug-file-directory', metavar='DEBUGDIR', - help='The directories for separate debug information \ - files. Multiple path components can be set concatenating \ - them by a path separator.') - args = parser.parse_args() - if args.path_to_cut: - fix_filename_patterns = args.path_to_cut - if args.demangle: - demangle = True - if args.s: - binary_name_filter = sysroot_path_filter - sysroot_path = args.s - if args.c: - binutils_prefix = args.c - if args.logfile: - logfile = args.logfile - else: - logfile = sys.stdin - if args.debug_file_directory: - separate_debug_dir_list = args.debug_file_directory.split(":") - if os.uname()[0] == 'Linux': - debug_info_handler = DebugInfoHandler(binary_name_filter) - binary_name_filter = debug_info_handler.get_debuginfo - loop = SymbolizationLoop(binary_name_filter) - loop.process_logfile() diff --git a/packaging/extract-ubsan-logs b/packaging/extract-ubsan-logs deleted file mode 100644 index d7a8ddf..0000000 --- a/packaging/extract-ubsan-logs +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -# /usr/lib/rpm/tizen/extract-ubsan-logs - -# If using normal root, avoid changing anything. -if [ -z "$RPM_BUILD_ROOT" -o "$RPM_BUILD_ROOT" = "/" ]; then - exit 0 -fi - -mkdir -p "$RPM_BUILD_ROOT/usr/share/ubsan" -find "/tmp/" -name 'ubsan.log*' | xargs -I {} cp {} "$RPM_BUILD_ROOT/usr/share/ubsan/" -find "$RPM_BUILD_ROOT/usr/share/ubsan/" -name 'ubsan.log*' | xargs -I {} sed -e "s#/.*rpmbuild/##" -i {} -find "$RPM_BUILD_ROOT/usr/share/ubsan/" -name 'ubsan.log*' -exec rename ubsan ${RPM_PACKAGE_NAME}-ubsan {} \; - -# Avoid empty resulting RPMs: create a placeholder if there's no logs in directory. -(find "$RPM_BUILD_ROOT/usr/share/ubsan/" -mindepth 1 -print -quit | grep -q .) || \ - touch "$RPM_BUILD_ROOT/usr/share/ubsan/ubsan.log.empty" diff --git a/packaging/gcc-aarch64.spec b/packaging/gcc-aarch64.spec index 538c288..1186204 100644 --- a/packaging/gcc-aarch64.spec +++ b/packaging/gcc-aarch64.spec @@ -91,16 +91,7 @@ Source10: gmp-6.1.1.tar.bz2 Source11: mpfr-3.1.5.tar.bz2 Source12: mpc-1.0.3.tar.gz Source13: isl-0.17.1.tar.bz2 -Source15: gcc-force-options -Source16: gcc-unforce-options -Source17: ASAN_OPTIONS -Source18: asan_symbolize.py -Source19: LSAN_OPTIONS Source20: gcc.manifest -Source21: UBSAN_OPTIONS -Source22: macros.ubsan -Source23: extract-ubsan-logs -Source24: lsan.supp Group: Development/Building Summary: The GNU C Compiler and Support Files License: GPL-3.0+ @@ -644,208 +635,6 @@ A foreign function interface is the popular name for the interface that allows c %post -n libgo-32bit -p /sbin/ldconfig %postun -n libgo-32bit -p /sbin/ldconfig -%package -n asan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc rpm -Requires: libasan - -%description -n asan-force-options -Scripts for ASan instrumentation - -%post -n asan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %asan_force_options -fno-common -# Add ASan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%asan_force_options %{asan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%asan_force_options -fno-common -%%restore_fcommon \\ - %%gcc_unforce_options \\ - %%gcc_force_options %%asan_force_options -fcommon -EOF -# ASan needs a whole shadow address space -# Using ulimit can only set the value for current user so we need to set /etc/security/limits.conf directly. -sed '/End of file/i\abuild\tsoft\tas\t-1\nabuild\thard\tas\t-1' -i /etc/security/limits.conf - -%preun -n asan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options -# Restore limit configurations set for ASan -sed '/abuild/d' -i /etc/security/limits.conf - -%package -n ubsan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc -Requires: libubsan - -%description -n ubsan-force-options -Scripts for UBSan instrumentation - -%post -n ubsan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %ubsan_force_options -# Add UBSan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%ubsan_force_options %{ubsan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%ubsan_force_options -EOF - -%preun -n ubsan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options - -%package -n ubsan-build-env -Summary: UBSan build environment -Group: System Environment -Requires: gcc -Requires: libubsan rpm - -%description -n ubsan-build-env -UBSan build environment support files and scripts - -%post -n ubsan-build-env -cat %{_rpmconfigdir}/macros.ubsan >> %{_rpmconfigdir}/tizen_macros - -%package -n lsan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc -Requires: liblsan - -%description -n lsan-force-options -Scripts for LSan instrumentation - -%post -n lsan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %lsan_force_options -# Add LSan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%lsan_force_options %{lsan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%lsan_force_options -EOF - -%preun -n lsan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ - -%package -n asan-build-env -Summary: Asan build environment -Group: Development/Libraries -Requires: libasan - -%description -n asan-build-env -Asan build environment - -%post -n asan-build-env -# Add /usr/lib/libasan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "libasan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload - -%preun -n asan-build-env -# Restore /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n lsan-runtime-env -Summary: LSan runtime environment -Group: Development/Libraries -Requires: liblsan -Requires(post): smack - -%description -n lsan-runtime-env -LSan runtime environment - -%post -n lsan-runtime-env -# Add /usr/lib64/liblsan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "%{libdir}/liblsan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload -echo "%{lsan_runtime_options}" > /LSAN_OPTIONS -chsmack -a "_" /etc/ld.so.preload /LSAN_OPTIONS /lsan.supp - -%preun -n lsan-runtime-env -# Restore /etc/ld.so.preload -mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n sanitizer-devel -Summary: Sanitizer platform-independent tools -License: MIT -Group: Development/Tools -BuildArch: noarch -Requires: binutils python -Requires(post): smack - -%description -n sanitizer-devel -The package contatins platform-independent tools for sanitization: -- asan_symbolize.py: script for offline symbolization of asan logs - -%package -n asan-runtime-env -Summary: Asan runtime environment for target device -Group: Development/Libraries -Requires: libasan - -%description -n asan-runtime-env -Asan runtime environment - -%post -n asan-runtime-env -# Add /usr/lib/libasan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "%{libdir}/libasan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload -echo "%{asan_runtime_options}" > /ASAN_OPTIONS -chsmack -a "_" /etc/ld.so.preload /ASAN_OPTIONS - -%preun -n asan-runtime-env -# Restore /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n ubsan-runtime-env -Summary: UBSan runtime environment for target device -Group: Development/Libraries -Requires: libubsan - -%description -n ubsan-runtime-env -UBSan runtime environment - -%post -n ubsan-runtime-env -echo "%{ubsan_runtime_options}" > /UBSAN_OPTIONS - %package plugin-devel Summary: GNU GCC Plugin development files License: GPL-3.0+ @@ -1033,31 +822,10 @@ rm -rf %{buildroot}/%{libsubdir}/include } %{!?cross: -sed -e 's|GCC_LIBSUBDIR|%{libsubdir}|' -i %{SOURCE15} - -cp %{SOURCE15} %{SOURCE16} %{SOURCE18} %{buildroot}%{_prefix}/bin -chmod a+x %{buildroot}%{_prefix}/bin/gcc-force-options -chmod a+x %{buildroot}%{_prefix}/bin/gcc-unforce-options -chmod a+x %{buildroot}%{_prefix}/bin/asan_symbolize.py - -cp %{SOURCE17} %{buildroot} -chmod 644 %{buildroot}/ASAN_OPTIONS - -%ifarch %lsan_arch -cp %{SOURCE19} %{SOURCE24} %{buildroot} -chmod 644 %{buildroot}/LSAN_OPTIONS -chmod 644 %{buildroot}/lsan.supp -%endif - cd ../ tar -czf libsanitizer.tar.bz libsanitizer mkdir -p %{buildroot}/src mv -v libsanitizer.tar.bz %{buildroot}/src - -mkdir -p %{buildroot}/%{_rpmconfigdir}/tizen/ -install -m 0644 %{SOURCE21} %{buildroot}/ -install -m 0644 %{SOURCE22} %{buildroot}/%{_rpmconfigdir}/ -install -m 0755 %{SOURCE23} %{buildroot}/%{_rpmconfigdir}/tizen/ } %files @@ -1337,53 +1105,6 @@ install -m 0755 %{SOURCE23} %{buildroot}/%{_rpmconfigdir}/tizen/ %{libsubdir}/32/libstdc++.so.*-gdb.py %endif -%files -n asan-force-options -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options - -%files -n ubsan-force-options -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options - -%ifarch %lsan_arch -%files -n lsan-force-options -%manifest gcc.manifest -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options -%endif - -%files -n asan-build-env -%defattr(-,root,root,-) -/ASAN_OPTIONS - -%files -n asan-runtime-env -%defattr(-,root,root,-) - -%ifarch %lsan_arch -%files -n lsan-runtime-env -%defattr(-,root,root,-) -/LSAN_OPTIONS -/lsan.supp -%endif - -%ifarch %ubsan_arch -%files -n ubsan-build-env -%defattr(-,root,root,-) -/UBSAN_OPTIONS -%{_rpmconfigdir}/macros.ubsan -%{_rpmconfigdir}/tizen/extract-ubsan-logs - -%files -n ubsan-runtime-env -%defattr(-,root,root,-) -%endif - -%files -n sanitizer-devel -%defattr(-,root,root,-) -%{_prefix}/bin/asan_symbolize.py - %files -n sanitizer-sources %defattr(-,root,root,-) /src/libsanitizer.tar.bz diff --git a/packaging/gcc-armv7l.spec b/packaging/gcc-armv7l.spec index a0e55e6..b80b764 100644 --- a/packaging/gcc-armv7l.spec +++ b/packaging/gcc-armv7l.spec @@ -91,16 +91,7 @@ Source10: gmp-6.1.1.tar.bz2 Source11: mpfr-3.1.5.tar.bz2 Source12: mpc-1.0.3.tar.gz Source13: isl-0.17.1.tar.bz2 -Source15: gcc-force-options -Source16: gcc-unforce-options -Source17: ASAN_OPTIONS -Source18: asan_symbolize.py -Source19: LSAN_OPTIONS Source20: gcc.manifest -Source21: UBSAN_OPTIONS -Source22: macros.ubsan -Source23: extract-ubsan-logs -Source24: lsan.supp Group: Development/Building Summary: The GNU C Compiler and Support Files License: GPL-3.0+ @@ -644,208 +635,6 @@ A foreign function interface is the popular name for the interface that allows c %post -n libgo-32bit -p /sbin/ldconfig %postun -n libgo-32bit -p /sbin/ldconfig -%package -n asan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc rpm -Requires: libasan - -%description -n asan-force-options -Scripts for ASan instrumentation - -%post -n asan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %asan_force_options -fno-common -# Add ASan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%asan_force_options %{asan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%asan_force_options -fno-common -%%restore_fcommon \\ - %%gcc_unforce_options \\ - %%gcc_force_options %%asan_force_options -fcommon -EOF -# ASan needs a whole shadow address space -# Using ulimit can only set the value for current user so we need to set /etc/security/limits.conf directly. -sed '/End of file/i\abuild\tsoft\tas\t-1\nabuild\thard\tas\t-1' -i /etc/security/limits.conf - -%preun -n asan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options -# Restore limit configurations set for ASan -sed '/abuild/d' -i /etc/security/limits.conf - -%package -n ubsan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc -Requires: libubsan - -%description -n ubsan-force-options -Scripts for UBSan instrumentation - -%post -n ubsan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %ubsan_force_options -# Add UBSan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%ubsan_force_options %{ubsan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%ubsan_force_options -EOF - -%preun -n ubsan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options - -%package -n ubsan-build-env -Summary: UBSan build environment -Group: System Environment -Requires: gcc -Requires: libubsan rpm - -%description -n ubsan-build-env -UBSan build environment support files and scripts - -%post -n ubsan-build-env -cat %{_rpmconfigdir}/macros.ubsan >> %{_rpmconfigdir}/tizen_macros - -%package -n lsan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc -Requires: liblsan - -%description -n lsan-force-options -Scripts for LSan instrumentation - -%post -n lsan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %lsan_force_options -# Add LSan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%lsan_force_options %{lsan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%lsan_force_options -EOF - -%preun -n lsan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ - -%package -n asan-build-env -Summary: Asan build environment -Group: Development/Libraries -Requires: libasan - -%description -n asan-build-env -Asan build environment - -%post -n asan-build-env -# Add /usr/lib/libasan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "libasan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload - -%preun -n asan-build-env -# Restore /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n lsan-runtime-env -Summary: LSan runtime environment -Group: Development/Libraries -Requires: liblsan -Requires(post): smack - -%description -n lsan-runtime-env -LSan runtime environment - -%post -n lsan-runtime-env -# Add /usr/lib64/liblsan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "%{libdir}/liblsan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload -echo "%{lsan_runtime_options}" > /LSAN_OPTIONS -chsmack -a "_" /etc/ld.so.preload /LSAN_OPTIONS /lsan.supp - -%preun -n lsan-runtime-env -# Restore /etc/ld.so.preload -mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n sanitizer-devel -Summary: Sanitizer platform-independent tools -License: MIT -Group: Development/Tools -BuildArch: noarch -Requires: binutils python -Requires(post): smack - -%description -n sanitizer-devel -The package contatins platform-independent tools for sanitization: -- asan_symbolize.py: script for offline symbolization of asan logs - -%package -n asan-runtime-env -Summary: Asan runtime environment for target device -Group: Development/Libraries -Requires: libasan - -%description -n asan-runtime-env -Asan runtime environment - -%post -n asan-runtime-env -# Add /usr/lib/libasan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "%{libdir}/libasan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload -echo "%{asan_runtime_options}" > /ASAN_OPTIONS -chsmack -a "_" /etc/ld.so.preload /ASAN_OPTIONS - -%preun -n asan-runtime-env -# Restore /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n ubsan-runtime-env -Summary: UBSan runtime environment for target device -Group: Development/Libraries -Requires: libubsan - -%description -n ubsan-runtime-env -UBSan runtime environment - -%post -n ubsan-runtime-env -echo "%{ubsan_runtime_options}" > /UBSAN_OPTIONS - %package plugin-devel Summary: GNU GCC Plugin development files License: GPL-3.0+ @@ -1033,31 +822,10 @@ rm -rf %{buildroot}/%{libsubdir}/include } %{!?cross: -sed -e 's|GCC_LIBSUBDIR|%{libsubdir}|' -i %{SOURCE15} - -cp %{SOURCE15} %{SOURCE16} %{SOURCE18} %{buildroot}%{_prefix}/bin -chmod a+x %{buildroot}%{_prefix}/bin/gcc-force-options -chmod a+x %{buildroot}%{_prefix}/bin/gcc-unforce-options -chmod a+x %{buildroot}%{_prefix}/bin/asan_symbolize.py - -cp %{SOURCE17} %{buildroot} -chmod 644 %{buildroot}/ASAN_OPTIONS - -%ifarch %lsan_arch -cp %{SOURCE19} %{SOURCE24} %{buildroot} -chmod 644 %{buildroot}/LSAN_OPTIONS -chmod 644 %{buildroot}/lsan.supp -%endif - cd ../ tar -czf libsanitizer.tar.bz libsanitizer mkdir -p %{buildroot}/src mv -v libsanitizer.tar.bz %{buildroot}/src - -mkdir -p %{buildroot}/%{_rpmconfigdir}/tizen/ -install -m 0644 %{SOURCE21} %{buildroot}/ -install -m 0644 %{SOURCE22} %{buildroot}/%{_rpmconfigdir}/ -install -m 0755 %{SOURCE23} %{buildroot}/%{_rpmconfigdir}/tizen/ } %files @@ -1337,53 +1105,6 @@ install -m 0755 %{SOURCE23} %{buildroot}/%{_rpmconfigdir}/tizen/ %{libsubdir}/32/libstdc++.so.*-gdb.py %endif -%files -n asan-force-options -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options - -%files -n ubsan-force-options -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options - -%ifarch %lsan_arch -%files -n lsan-force-options -%manifest gcc.manifest -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options -%endif - -%files -n asan-build-env -%defattr(-,root,root,-) -/ASAN_OPTIONS - -%files -n asan-runtime-env -%defattr(-,root,root,-) - -%ifarch %lsan_arch -%files -n lsan-runtime-env -%defattr(-,root,root,-) -/LSAN_OPTIONS -/lsan.supp -%endif - -%ifarch %ubsan_arch -%files -n ubsan-build-env -%defattr(-,root,root,-) -/UBSAN_OPTIONS -%{_rpmconfigdir}/macros.ubsan -%{_rpmconfigdir}/tizen/extract-ubsan-logs - -%files -n ubsan-runtime-env -%defattr(-,root,root,-) -%endif - -%files -n sanitizer-devel -%defattr(-,root,root,-) -%{_prefix}/bin/asan_symbolize.py - %files -n sanitizer-sources %defattr(-,root,root,-) /src/libsanitizer.tar.bz diff --git a/packaging/gcc-force-options b/packaging/gcc-force-options deleted file mode 100644 index 5813d78..0000000 --- a/packaging/gcc-force-options +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/sh - -set -e - -if [ $# -eq 0 ]; then - cat << EOF -Syntax: - $(basename $0) OPT1 [OPT2...]" - -Example: - $(basename $0) [prepend|append] -fsanitize=address -fno-common -U_FORTIFY_SOURCE - By default flags are appending. -EOF - exit 1 -fi - -if [ $(find $(dirname $0) -name \*-real | wc -l) -gt 0 ]; then - echo >&2 "$(basename $0): directory was already processed, aborting" - exit 1 -fi - -FLAGS="" -LD_FLAGS="" - -function divide_flags { - NEED_LIB_NAME="N" - for f in "$@"; do - case $f in - -l) - NEED_LIB_NAME="Y" - ;; - - -l*) - LDFLAGS="$LDFLAGS $f" - ;; - - -Wl,*) - LDFLAGS="$LDFLAGS ${f:4}" - ;; - - *) - if [ "$NEED_LIB_NAME" = "Y" ]; then - LDFLAGS="$LDFLAGS -l$f" - NEED_LIB_NAME="N" - else - FLAGS="$FLAGS $f" - fi - esac - done -} - -case "$1" in -prepend) - shift - divide_flags $@ - PREFLAGS=$FLAGS - POSTFLAGS= - LD_PREFLAGS=$LDFLAGS - LD_POSTFLAGS= - ;; -append) - shift - divide_flags $@ - PREFLAGS= - POSTFLAGS=$FLAGS - LD_PREFLAGS= - LD_POSTFLAGS=$LDFLAGS - ;; -*) - divide_flags $@ - PREFLAGS= - POSTFLAGS=$FLAGS - LD_PREFLAGS= - LD_POSTFLAGS=$LDFLAGS - ;; -esac - -TMP=$(pwd)/tmp.$$ -cat > $TMP << EOF -#!/bin/sh -if echo "$PREFLAGS "\$@" $POSTFLAGS" | grep -q -- "-fsanitize=undefined" && echo "\$@" | grep -q "\.gch\>"; then - # UBSan doesn't support precompiled headers. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66343 - echo "Precompiled headers currently not supported by UBSan" >&2 - # Don't instrument kernel modules - # Don't instrument with "-nostdlib" linking -elif ! echo "\$@" | grep -q -e __KERNEL__ -e \-nostdlib; then - # Use readlink in order to follow symlinks if any - \$(readlink -f \$0)-real $PREFLAGS "\$@" $POSTFLAGS -else - # -Wl,--tizen-no-force-options is used to tell collect2 to not add force - # options. It will be removed in collect2. - \$(readlink -f \$0)-real "\$@" -Wl,--tizen-no-force-options -fi -EOF -chmod +x $TMP - -find -L $(dirname $0) -type f -a -perm -a=x | grep -E '(gcc|g\+\+|c\+\+)$' | while read tool; do - mv $tool $tool-real - cp $TMP $tool -done - -LD_TMP=$(pwd)/ld_tmp.$$ -cat > $LD_TMP << EOF -#!/bin/sh -if ! echo "\$@" | grep -q -e \-\-tizen\-no\-force\-options; then - # Use readlink in order to follow symlinks if any - \$(readlink -f \$0)-real $LD_PREFLAGS "\$@" $LD_POSTFLAGS -else - # Remove --tizen-no-force-options from the argument list - FLAGS=\$(echo \$@ | sed -e 's/--tizen-no-force-options//g') - \$(readlink -f \$0)-real \$FLAGS -fi -EOF -chmod +x $LD_TMP - -find -L GCC_LIBSUBDIR -type f -a -perm -a=x -name 'collect2' | while read tool; do - mv $tool $tool-real - cp $LD_TMP $tool -done - -if [ -d /emul ]; then - find -L /emul -type f -a -perm -a=x | grep -E '(gcc|g\+\+|c\+\+|collect2)$' | while read tool; do - ln -sf $(basename $tool) $tool-real - done -fi - -rm $TMP -rm $LD_TMP - diff --git a/packaging/gcc-unforce-options b/packaging/gcc-unforce-options deleted file mode 100644 index 7e85b75..0000000 --- a/packaging/gcc-unforce-options +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -set -e - -if [ $# -gt 0 ]; then - echo >&2 "$(basename $0): unexpected arguments" - exit 1 -fi - -find $(dirname $0) /usr/*/gcc -name \*-real | while read tool_real; do - tool=$(echo "$tool_real" | sed -e 's/-real$//') - mv $tool_real $tool -done -if [ -d /emul ]; then - find /emul -name \*-real | while read tool_real; do - rm $tool_real - done -fi - diff --git a/packaging/linaro-gcc.spec b/packaging/linaro-gcc.spec index aebe780..f760a02 100644 --- a/packaging/linaro-gcc.spec +++ b/packaging/linaro-gcc.spec @@ -88,16 +88,7 @@ Source10: gmp-6.1.1.tar.bz2 Source11: mpfr-3.1.5.tar.bz2 Source12: mpc-1.0.3.tar.gz Source13: isl-0.17.1.tar.bz2 -Source15: gcc-force-options -Source16: gcc-unforce-options -Source17: ASAN_OPTIONS -Source18: asan_symbolize.py -Source19: LSAN_OPTIONS Source20: gcc.manifest -Source21: UBSAN_OPTIONS -Source22: macros.ubsan -Source23: extract-ubsan-logs -Source24: lsan.supp Group: Development/Building Summary: The GNU C Compiler and Support Files License: GPL-3.0+ @@ -641,208 +632,6 @@ A foreign function interface is the popular name for the interface that allows c %post -n libgo-32bit -p /sbin/ldconfig %postun -n libgo-32bit -p /sbin/ldconfig -%package -n asan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc rpm -Requires: libasan - -%description -n asan-force-options -Scripts for ASan instrumentation - -%post -n asan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %asan_force_options -fno-common -# Add ASan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%asan_force_options %{asan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%asan_force_options -fno-common -%%restore_fcommon \\ - %%gcc_unforce_options \\ - %%gcc_force_options %%asan_force_options -fcommon -EOF -# ASan needs a whole shadow address space -# Using ulimit can only set the value for current user so we need to set /etc/security/limits.conf directly. -sed '/End of file/i\abuild\tsoft\tas\t-1\nabuild\thard\tas\t-1' -i /etc/security/limits.conf - -%preun -n asan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options -# Restore limit configurations set for ASan -sed '/abuild/d' -i /etc/security/limits.conf - -%package -n ubsan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc -Requires: libubsan - -%description -n ubsan-force-options -Scripts for UBSan instrumentation - -%post -n ubsan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %ubsan_force_options -# Add UBSan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%ubsan_force_options %{ubsan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%ubsan_force_options -EOF - -%preun -n ubsan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options - -%package -n ubsan-build-env -Summary: UBSan build environment -Group: System Environment -Requires: gcc -Requires: libubsan rpm - -%description -n ubsan-build-env -UBSan build environment support files and scripts - -%post -n ubsan-build-env -cat %{_rpmconfigdir}/macros.ubsan >> %{_rpmconfigdir}/tizen_macros - -%package -n lsan-force-options -Summary: Scripts to enable automatic package sanitization -Group: System Environment -Requires: gcc -Requires: liblsan - -%description -n lsan-force-options -Scripts for LSan instrumentation - -%post -n lsan-force-options -# Change mode to allow all users to run gcc-force/unforce-options -chmod a+w /usr/bin -chmod a+w %{libsubdir} -[ -d /emul/ ] && chmod a+w /emul/usr/bin/ && chmod a+w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a+w -/usr/bin/gcc-force-options %lsan_force_options -# Add LSan-related macros -cat >> /usr/lib/rpm/tizen_macros << EOF - -%%lsan_force_options %{lsan_force_options} -%%gcc_unforce_options /usr/bin/gcc-unforce-options -%%gcc_force_options /usr/bin/gcc-force-options -%%gcc_force_default_options %%gcc_force_options %%lsan_force_options -EOF - -%preun -n lsan-force-options -# Restore read-only mode -chmod a-w /usr/bin -chmod a-w %{libsubdir} -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ && chmod a-w /emul/home/abuild/rpmbuild/BUILD/gcc-%{version}/obj/gcc/ \ - && find -L /emul/usr/*/gcc -name 'collect2' | xargs dirname | xargs chmod a-w -/usr/bin/gcc-unforce-options -[ -d /emul/ ] && chmod a-w /emul/usr/bin/ - -%package -n asan-build-env -Summary: Asan build environment -Group: Development/Libraries -Requires: libasan - -%description -n asan-build-env -Asan build environment - -%post -n asan-build-env -# Add /usr/lib/libasan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "libasan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload - -%preun -n asan-build-env -# Restore /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n lsan-runtime-env -Summary: LSan runtime environment -Group: Development/Libraries -Requires: liblsan -Requires(post): smack - -%description -n lsan-runtime-env -LSan runtime environment - -%post -n lsan-runtime-env -# Add /usr/lib64/liblsan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "%{libdir}/liblsan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload -echo "%{lsan_runtime_options}" > /LSAN_OPTIONS -chsmack -a "_" /etc/ld.so.preload /LSAN_OPTIONS /lsan.supp - -%preun -n lsan-runtime-env -# Restore /etc/ld.so.preload -mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n sanitizer-devel -Summary: Sanitizer platform-independent tools -License: MIT -Group: Development/Tools -BuildArch: noarch -Requires: binutils python -Requires(post): smack - -%description -n sanitizer-devel -The package contatins platform-independent tools for sanitization: -- asan_symbolize.py: script for offline symbolization of asan logs - -%package -n asan-runtime-env -Summary: Asan runtime environment for target device -Group: Development/Libraries -Requires: libasan - -%description -n asan-runtime-env -Asan runtime environment - -%post -n asan-runtime-env -# Add /usr/lib/libasan.so to /etc/ld.so.preload -[ -f /etc/ld.so.preload ] && mv -v /etc/ld.so.preload /etc/ld.so.preload.orig -echo "%{libdir}/libasan.so" > /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && cat /etc/ld.so.preload.orig >> /etc/ld.so.preload -echo "%{asan_runtime_options}" > /ASAN_OPTIONS -chsmack -a "_" /etc/ld.so.preload /ASAN_OPTIONS - -%preun -n asan-runtime-env -# Restore /etc/ld.so.preload -[ -f /etc/ld.so.preload.orig ] && mv -v /etc/ld.so.preload.orig /etc/ld.so.preload - -%package -n ubsan-runtime-env -Summary: UBSan runtime environment for target device -Group: Development/Libraries -Requires: libubsan - -%description -n ubsan-runtime-env -UBSan runtime environment - -%post -n ubsan-runtime-env -echo "%{ubsan_runtime_options}" > /UBSAN_OPTIONS - %package plugin-devel Summary: GNU GCC Plugin development files License: GPL-3.0+ @@ -1030,31 +819,10 @@ rm -rf %{buildroot}/%{libsubdir}/include } %{!?cross: -sed -e 's|GCC_LIBSUBDIR|%{libsubdir}|' -i %{SOURCE15} - -cp %{SOURCE15} %{SOURCE16} %{SOURCE18} %{buildroot}%{_prefix}/bin -chmod a+x %{buildroot}%{_prefix}/bin/gcc-force-options -chmod a+x %{buildroot}%{_prefix}/bin/gcc-unforce-options -chmod a+x %{buildroot}%{_prefix}/bin/asan_symbolize.py - -cp %{SOURCE17} %{buildroot} -chmod 644 %{buildroot}/ASAN_OPTIONS - -%ifarch %lsan_arch -cp %{SOURCE19} %{SOURCE24} %{buildroot} -chmod 644 %{buildroot}/LSAN_OPTIONS -chmod 644 %{buildroot}/lsan.supp -%endif - cd ../ tar -czf libsanitizer.tar.bz libsanitizer mkdir -p %{buildroot}/src mv -v libsanitizer.tar.bz %{buildroot}/src - -mkdir -p %{buildroot}/%{_rpmconfigdir}/tizen/ -install -m 0644 %{SOURCE21} %{buildroot}/ -install -m 0644 %{SOURCE22} %{buildroot}/%{_rpmconfigdir}/ -install -m 0755 %{SOURCE23} %{buildroot}/%{_rpmconfigdir}/tizen/ } %files @@ -1334,53 +1102,6 @@ install -m 0755 %{SOURCE23} %{buildroot}/%{_rpmconfigdir}/tizen/ %{libsubdir}/32/libstdc++.so.*-gdb.py %endif -%files -n asan-force-options -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options - -%files -n ubsan-force-options -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options - -%ifarch %lsan_arch -%files -n lsan-force-options -%manifest gcc.manifest -%defattr(-,root,root,-) -%{_prefix}/bin/gcc-force-options -%{_prefix}/bin/gcc-unforce-options -%endif - -%files -n asan-build-env -%defattr(-,root,root,-) -/ASAN_OPTIONS - -%files -n asan-runtime-env -%defattr(-,root,root,-) - -%ifarch %lsan_arch -%files -n lsan-runtime-env -%defattr(-,root,root,-) -/LSAN_OPTIONS -/lsan.supp -%endif - -%ifarch %ubsan_arch -%files -n ubsan-build-env -%defattr(-,root,root,-) -/UBSAN_OPTIONS -%{_rpmconfigdir}/macros.ubsan -%{_rpmconfigdir}/tizen/extract-ubsan-logs - -%files -n ubsan-runtime-env -%defattr(-,root,root,-) -%endif - -%files -n sanitizer-devel -%defattr(-,root,root,-) -%{_prefix}/bin/asan_symbolize.py - %files -n sanitizer-sources %defattr(-,root,root,-) /src/libsanitizer.tar.bz diff --git a/packaging/lsan.supp b/packaging/lsan.supp deleted file mode 100644 index 7189406..0000000 --- a/packaging/lsan.supp +++ /dev/null @@ -1 +0,0 @@ -leak:g_hash_table_new_full diff --git a/packaging/macros.ubsan b/packaging/macros.ubsan deleted file mode 100644 index 652a49b..0000000 --- a/packaging/macros.ubsan +++ /dev/null @@ -1,39 +0,0 @@ -# /etc/rpm/macros.ubsan - -%_enable_ubsan_packages 1 - -%__ubsan_install_post %{_rpmconfigdir}/tizen/extract-ubsan-logs - -# See original macro (before expansion) and correct lines after the first one. -# Mine is from Fedora RPM macros, YMMV. -%__spec_install_post\ - %{?__ubsan_package:%{__ubsan_install_post}}\ - %{?__debug_package:%{__debug_install_post}}\ - %{__arch_install_post}\ - %{__os_install_post}\ -%{nil} - -# Same goes here, see your original macro. -%install %{?_enable_ubsan_packages:%{ubsan_package}}\ -%{?_enable_debug_packages:%{debug_package}}\ -%%install\ -LANG=C\ -export LANG\ -unset DISPLAY\ -rm -rf %{?buildroot:%{buildroot}} \ -mkdir -p %{?buildroot:%{buildroot}} \ -%{nil} - -# Template for ubsan logs sub-package. -%ubsan_package \ -%global __ubsan_package 1\ -%package ubsan-logs\ -Summary: UBSan logs for package %{name}\ -Group: Development/UBSan\ -AutoReqProv: 0\ -%description ubsan-logs\ -This package provides UBSan log files for package %{name}.\ -%files ubsan-logs\ -%defattr(-,root,root)\ -/usr/share/ubsan/*ubsan.log*\ -%{nil} -- 2.7.4 From 6bffedf09ffc5c2b6e1c65dac4ad864d35a45821 Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 24 Jan 2017 00:18:36 +0000 Subject: [PATCH 03/16] Fixed aarch64 build. PR sanitizer/79168 * merge.sh (change_comment_headers): Don't remove 2nd and 3rd line if the 3rd line doesn't contain 'The LLVM Compiler Infrastructure' text. * sanitizer_common/sanitizer_linux_mips64.S: Regenerated. * sanitizer_common/sanitizer_linux_x86_64.S: Likewise. * tsan/tsan_ppc_regs.h: Likewise. * tsan/tsan_rtl_aarch64.S: Likewise. * tsan/tsan_rtl_mips64.S: Likewise. * tsan/tsan_rtl_ppc64.S: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@244844 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I384d6d121d2e0fcd2947400c14082f7b83e8cb20 Signed-off-by: Michail Kashkarov --- libsanitizer/merge.sh | 1 + libsanitizer/sanitizer_common/sanitizer_linux_mips64.S | 2 ++ libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S | 2 ++ libsanitizer/tsan/tsan_interceptors.h | 2 ++ libsanitizer/tsan/tsan_ppc_regs.h | 2 ++ libsanitizer/tsan/tsan_rtl_aarch64.S | 2 ++ libsanitizer/tsan/tsan_rtl_mips64.S | 2 ++ libsanitizer/tsan/tsan_rtl_ppc64.S | 2 ++ 8 files changed, 15 insertions(+) diff --git a/libsanitizer/merge.sh b/libsanitizer/merge.sh index b332102..2e5ec25 100755 --- a/libsanitizer/merge.sh +++ b/libsanitizer/merge.sh @@ -22,6 +22,7 @@ list_files() { change_comment_headers() { for f in $(list_files $1); do + sed -n 3p $1/$f | grep -q 'The LLVM Compiler Infrastructure' || continue changed=$(awk 'NR != 2 && NR != 3' < $1/$f) echo "$changed" > $1/$f done diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_mips64.S b/libsanitizer/sanitizer_common/sanitizer_linux_mips64.S index 0b76f3a..8729642 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_mips64.S +++ b/libsanitizer/sanitizer_common/sanitizer_linux_mips64.S @@ -1,4 +1,6 @@ // This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + // Avoid being marked as needing an executable stack: #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S b/libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S index 6b89211..8ff9095 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S +++ b/libsanitizer/sanitizer_common/sanitizer_linux_x86_64.S @@ -1,4 +1,6 @@ // This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. + // Avoid being marked as needing an executable stack: #if defined(__linux__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits diff --git a/libsanitizer/tsan/tsan_interceptors.h b/libsanitizer/tsan/tsan_interceptors.h index 97fa508..a0f9a07 100644 --- a/libsanitizer/tsan/tsan_interceptors.h +++ b/libsanitizer/tsan/tsan_interceptors.h @@ -1,4 +1,6 @@ #ifndef TSAN_INTERCEPTORS_H +#define TSAN_INTERCEPTORS_H + #include "sanitizer_common/sanitizer_stacktrace.h" #include "tsan_rtl.h" diff --git a/libsanitizer/tsan/tsan_ppc_regs.h b/libsanitizer/tsan/tsan_ppc_regs.h index 15bd10a..5b43f3d 100644 --- a/libsanitizer/tsan/tsan_ppc_regs.h +++ b/libsanitizer/tsan/tsan_ppc_regs.h @@ -1,4 +1,6 @@ #define r0 0 +#define r1 1 +#define r2 2 #define r3 3 #define r4 4 #define r5 5 diff --git a/libsanitizer/tsan/tsan_rtl_aarch64.S b/libsanitizer/tsan/tsan_rtl_aarch64.S index ab5a830..ef06f04 100644 --- a/libsanitizer/tsan/tsan_rtl_aarch64.S +++ b/libsanitizer/tsan/tsan_rtl_aarch64.S @@ -1,4 +1,6 @@ #include "sanitizer_common/sanitizer_asm.h" + +.section .bss .type __tsan_pointer_chk_guard, %object .size __tsan_pointer_chk_guard, 8 __tsan_pointer_chk_guard: diff --git a/libsanitizer/tsan/tsan_rtl_mips64.S b/libsanitizer/tsan/tsan_rtl_mips64.S index b1c9d8b..d0f7a3f 100644 --- a/libsanitizer/tsan/tsan_rtl_mips64.S +++ b/libsanitizer/tsan/tsan_rtl_mips64.S @@ -1,4 +1,6 @@ .section .text +.set noreorder + .hidden __tsan_setjmp .comm _ZN14__interception11real_setjmpE,8,8 .globl setjmp diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S index 81d309f..8285e21 100644 --- a/libsanitizer/tsan/tsan_rtl_ppc64.S +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S @@ -1,4 +1,6 @@ #include "tsan_ppc_regs.h" + + .section .text .hidden __tsan_setjmp .globl _setjmp .type _setjmp, @function -- 2.7.4 From ce8f98b15cfa686de845dfa6d0e256ed9484681c Mon Sep 17 00:00:00 2001 From: Dongkyun Son Date: Sat, 2 Sep 2017 00:35:56 +0900 Subject: [PATCH 04/16] packaging: provide libasan(64bit) on 32bit build env This is needed as it requires 64bit libs into i586 repo, sometimes. (e.g, .NET toolchain asan build). Change-Id: Ia18f132b19e8552b347132531f3e12000aa34514 Signed-off-by: Dongkyun Son --- packaging/baselibs.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packaging/baselibs.conf b/packaging/baselibs.conf index c1a4523..a821103 100644 --- a/packaging/baselibs.conf +++ b/packaging/baselibs.conf @@ -3,3 +3,5 @@ libstdc++ targettype 32bit block! libgcc targettype 32bit block! +libasan + targettype 32bit block! -- 2.7.4 From 1653f8a22c83b08c4aea20cfd9f427740a1f7b40 Mon Sep 17 00:00:00 2001 From: Dongkyun Son Date: Tue, 19 Sep 2017 14:33:20 +0900 Subject: [PATCH 05/16] packaging: clean-up sanitizer macros. sanitizer related macros moved to 'gcc-contrib' package. Change-Id: Ic8ed52aac4a502f2bf44053225b2e29e721699d6 Signed-off-by: Dongkyun Son --- ChangeLog.Tizen | 20 ++++++++++++++++++++ packaging/gcc-aarch64.spec | 8 -------- packaging/gcc-armv7l.spec | 8 -------- packaging/linaro-gcc.spec | 8 -------- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/ChangeLog.Tizen b/ChangeLog.Tizen index 8d820cf..f1ebf58 100644 --- a/ChangeLog.Tizen +++ b/ChangeLog.Tizen @@ -30,8 +30,28 @@ # file after the commit hash is fixed, you are free to add the commit hash. ################################################################################ +2017-09-26 Dongkyun Son + + packaging: clean-up sanitizer macros. + +2017-09-14 Dongkyun Son + + commit ce8f98b15cfa686de845dfa6d0e256ed9484681c + packaging: provide libasan(64bit) on 32bit build env + +2017-09-11 Denis Khalikov + + commit bdfd925eda6c0c5857fe9282e973516ac8bedb9f + [TTC-6] packaging: Support for gcc-contrib. + +2017-09-04 Slava Barinov + + commit 91971721b75fcd6c83a36a72b0a8d7bb3ec1e91e + [TTC-5] Forbid section anchors for ASan build (PR sanitizer/81697) + 2017-08-30 Sangmin Seo + commit f82588bbb3fe09f23a1e685e1506cf962c951da3 Add ChangeLog.Tizen 2017-08-30 Hoyub Lee diff --git a/packaging/gcc-aarch64.spec b/packaging/gcc-aarch64.spec index 1186204..b6e8af4 100644 --- a/packaging/gcc-aarch64.spec +++ b/packaging/gcc-aarch64.spec @@ -54,14 +54,6 @@ %define libdir %{!?cross:%{_libdir}}%{?cross:%{_prefix}/lib%{?aarch64:64}} %define libsubdir %{libdir}/gcc/%{target_arch}/%{version} -%define asan_force_options -fsanitize-recover=address -fsanitize=address -fno-omit-frame-pointer -Wp,-U_FORTIFY_SOURCE -Wl,--as-needed -ldl -lpthread -%define ubsan_force_options -fsanitize=undefined,bounds-strict,float-divide-by-zero,float-cast-overflow -%define lsan_force_options -fsanitize=leak -fno-omit-frame-pointer -Wp,-U_FORTIFY_SOURCE - -%define asan_runtime_options halt_on_error=false:start_deactivated=true:print_cmdline=true:quarantine_size_mb=1:detect_leaks=0:log_path=/tmp/asan.log:log_exe_name=1 -%define ubsan_runtime_options print_cmdline=true:log_path=/tmp/ubsan.log -%define lsan_runtime_options print_cmdline=true:detect_leaks=1:log_path=/tmp/lsan.log:log_exe_name=1:fast_unwind_on_malloc=false:malloc_context_size=5:suppressions=/lsan.supp:print_suppressions=false - Name: gcc%{?cross:-%{cross}} # With generated files in src we could drop the following BuildRequires: bison diff --git a/packaging/gcc-armv7l.spec b/packaging/gcc-armv7l.spec index b80b764..0d7655d 100644 --- a/packaging/gcc-armv7l.spec +++ b/packaging/gcc-armv7l.spec @@ -54,14 +54,6 @@ %define libdir %{!?cross:%{_libdir}}%{?cross:%{_prefix}/lib%{?aarch64:64}} %define libsubdir %{libdir}/gcc/%{target_arch}/%{version} -%define asan_force_options -fsanitize-recover=address -fsanitize=address -fno-omit-frame-pointer -Wp,-U_FORTIFY_SOURCE -Wl,--as-needed -ldl -lpthread -%define ubsan_force_options -fsanitize=undefined,bounds-strict,float-divide-by-zero,float-cast-overflow -%define lsan_force_options -fsanitize=leak -fno-omit-frame-pointer -Wp,-U_FORTIFY_SOURCE - -%define asan_runtime_options halt_on_error=false:start_deactivated=true:print_cmdline=true:quarantine_size_mb=1:detect_leaks=0:log_path=/tmp/asan.log:log_exe_name=1 -%define ubsan_runtime_options print_cmdline=true:log_path=/tmp/ubsan.log -%define lsan_runtime_options print_cmdline=true:detect_leaks=1:log_path=/tmp/lsan.log:log_exe_name=1:fast_unwind_on_malloc=false:malloc_context_size=5:suppressions=/lsan.supp:print_suppressions=false - Name: gcc%{?cross:-%{cross}} # With generated files in src we could drop the following BuildRequires: bison diff --git a/packaging/linaro-gcc.spec b/packaging/linaro-gcc.spec index f760a02..fd937c3 100644 --- a/packaging/linaro-gcc.spec +++ b/packaging/linaro-gcc.spec @@ -51,14 +51,6 @@ %define libdir %{!?cross:%{_libdir}}%{?cross:%{_prefix}/lib%{?aarch64:64}} %define libsubdir %{libdir}/gcc/%{target_arch}/%{version} -%define asan_force_options -fsanitize-recover=address -fsanitize=address -fno-omit-frame-pointer -Wp,-U_FORTIFY_SOURCE -Wl,--as-needed -ldl -lpthread -%define ubsan_force_options -fsanitize=undefined,bounds-strict,float-divide-by-zero,float-cast-overflow -%define lsan_force_options -fsanitize=leak -fno-omit-frame-pointer -Wp,-U_FORTIFY_SOURCE - -%define asan_runtime_options halt_on_error=false:start_deactivated=true:print_cmdline=true:quarantine_size_mb=1:detect_leaks=0:log_path=/tmp/asan.log:log_exe_name=1 -%define ubsan_runtime_options print_cmdline=true:log_path=/tmp/ubsan.log -%define lsan_runtime_options print_cmdline=true:detect_leaks=1:log_path=/tmp/lsan.log:log_exe_name=1:fast_unwind_on_malloc=false:malloc_context_size=5:suppressions=/lsan.supp:print_suppressions=false - Name: gcc%{?cross:-%{cross}} # With generated files in src we could drop the following BuildRequires: bison -- 2.7.4 From 5827371affb63bc4b527847371990b20065df667 Mon Sep 17 00:00:00 2001 From: Mikhail Kashkarov Date: Fri, 5 May 2017 17:00:49 +0300 Subject: [PATCH 06/16] Add armv7hl support. Change-Id: Ib611ee4659af5e30b2a9c46ded7588b5a5c139fa --- packaging/gcc-aarch64.spec | 18 +- packaging/gcc-armv7hl.spec | 1122 ++++++++++++++++++++++++++++++++++++++++++++ packaging/gcc-armv7l.spec | 18 +- packaging/linaro-gcc.spec | 18 +- packaging/pre_checkin.sh | 2 +- 5 files changed, 1174 insertions(+), 4 deletions(-) create mode 100644 packaging/gcc-armv7hl.spec diff --git a/packaging/gcc-aarch64.spec b/packaging/gcc-aarch64.spec index b6e8af4..edce6d1 100644 --- a/packaging/gcc-aarch64.spec +++ b/packaging/gcc-aarch64.spec @@ -36,6 +36,10 @@ %define ARCH armv7l %define ABI eabi %endif +%ifarch armv7hl +%define ARCH armv7hl +%define ABI eabihf +%endif %ifarch %ix86 %define ARCH i586 %endif @@ -48,7 +52,7 @@ %define host_arch %{ARCH}-tizen-linux-gnu%{?ABI} %define target_cpu %{?cross}%{!?cross:%{ARCH}} -%define target_abi %{?cross:%{?armv7l:eabi}}%{!?cross:%{?ABI}} +%define target_abi %{?cross:%{?armv7l:eabi}%{?armv7hl:eabihf}}%{!?cross:%{?ABI}} %define target_arch %{target_cpu}-tizen-linux-gnu%{?target_abi} %define libdir %{!?cross:%{_libdir}}%{?cross:%{_prefix}/lib%{?aarch64:64}} @@ -714,6 +718,12 @@ TCFLAGS="$RPM_OPT_FLAGS" GCJFLAGS="$RPM_OPT_FLAGS" \ --with-tune=cortex-a8 \ --disable-sjlj-exceptions \ %endif +%ifarch armv7hl + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +%endif %ifarch aarch64 --with-arch=armv8-a \ --disable-sjlj-exceptions \ @@ -736,6 +746,12 @@ TCFLAGS="$RPM_OPT_FLAGS" GCJFLAGS="$RPM_OPT_FLAGS" \ --with-tune=cortex-a8 \ --disable-sjlj-exceptions \ } \ +%{?armv7hl: \ + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +} \ %{?aarch64: \ --with-arch=armv8-a \ --disable-sjlj-exceptions \ diff --git a/packaging/gcc-armv7hl.spec b/packaging/gcc-armv7hl.spec new file mode 100644 index 0000000..f28b8d1 --- /dev/null +++ b/packaging/gcc-armv7hl.spec @@ -0,0 +1,1122 @@ +%define cross armv7hl +%define armv7hl 1 + +# +# spec file for package gcc6 +# +# Copyright (c) 2009 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 Tizen +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.tizen.org/ +# +# we use %%{?macro: ... } as it is more compact +%if 0%{?run_tests} +%define gcc_run_tests 1 +%endif + +%define quadmath_arch %ix86 x86_64 ia64 +%define tsan_arch x86_64 aarch64 +%define asan_arch x86_64 %ix86 ppc ppc64 %sparc %arm aarch64 +%define itm_arch x86_64 %ix86 %arm ppc ppc64 ppc64le s390 s390x %sparc aarch64 +%define atomic_arch x86_64 %ix86 %arm aarch64 ppc ppc64 ppc64le s390 s390x %sparc m68k +%define lsan_arch x86_64 %ix86 armv7l aarch64 +%define ubsan_arch x86_64 %ix86 ppc ppc64 %arm aarch64 +%define cilkrts_arch x86_64 %ix86 + +%ifarch armv7l +%define ARCH armv7l +%define ABI eabi +%endif +%ifarch armv7hl +%define ARCH armv7hl +%define ABI eabihf +%endif +%ifarch %ix86 +%define ARCH i586 +%endif +%ifarch x86_64 +%define ARCH x86_64 +%endif +%ifarch aarch64 +%define ARCH aarch64 +%endif +%define host_arch %{ARCH}-tizen-linux-gnu%{?ABI} + +%define target_cpu %{?cross}%{!?cross:%{ARCH}} +%define target_abi %{?cross:%{?armv7l:eabi}%{?armv7hl:eabihf}}%{!?cross:%{?ABI}} + +%define target_arch %{target_cpu}-tizen-linux-gnu%{?target_abi} +%define libdir %{!?cross:%{_libdir}}%{?cross:%{_prefix}/lib%{?aarch64:64}} +%define libsubdir %{libdir}/gcc/%{target_arch}/%{version} + +Name: gcc%{?cross:-%{cross}} +# With generated files in src we could drop the following +BuildRequires: bison +BuildRequires: flex +BuildRequires: gettext-devel +BuildRequires: makeinfo +## until here, but at least renaming and patching info files breaks this +BuildRequires: gcc-c++ +BuildRequires: zlib-devel +%ifarch x86_64 +BuildRequires: glibc-devel-32bit +%endif +BuildRequires: perl +%{?cross:BuildRequires: binutils-%{cross}} +# here we use %%if because OBS spec parser cannot expand +# %%{?macro:...} correctly +%if 0%{?gcc_run_tests} +BuildRequires: dejagnu +BuildRequires: expect +BuildRequires: gdb +%endif +URL: http://gcc.gnu.org/ +Version: 6.2.1 +Release: 0 +Source: gcc-%{version}.tar.bz2 +Source10: gmp-6.1.1.tar.bz2 +Source11: mpfr-3.1.5.tar.bz2 +Source12: mpc-1.0.3.tar.gz +Source13: isl-0.17.1.tar.bz2 +Source20: gcc.manifest +Group: Development/Building +Summary: The GNU C Compiler and Support Files +License: GPL-3.0+ +%{?cross:ExcludeArch: %{cross}} +%description +Core package for the GNU Compiler Collection, including the C language +frontend. + +%package c++ +Summary: The GNU C++ Compiler +License: GPL-3.0+ +Group: Development/Languages +%description c++ +This package contains the GNU compiler for C++. + +%package -n libstdc++ +Summary: The standard C++ shared library +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libstdc++ +The standard C++ library, needed for dynamically linked C++ programs. +%post -n libstdc++ -p /sbin/ldconfig +%postun -n libstdc++ -p /sbin/ldconfig + +%package -n libstdc++-devel +Summary: Include Files and Libraries mandatory for Development +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libstdc++-devel +This package contains all the headers and libraries of the standard C++ +library. It is needed for compiling C++ code. + +%package -n libgcc +Summary: C compiler runtime library +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libgcc +Libgcc is needed for dynamically linked C programs. +%post -n libgcc -p /sbin/ldconfig +%postun -n libgcc -p /sbin/ldconfig + +%package -n libgomp +Summary: The GNU compiler collection OpenMP runtime library +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libgomp +This is the OpenMP runtime library needed by OpenMP enabled programs +that were built with the -fopenmp compiler option and by programs that +were auto-parallelized via the -ftree-parallelize-loops compiler +option. +%post -n libgomp -p /sbin/ldconfig +%postun -n libgomp -p /sbin/ldconfig + +%package objc +Summary: GNU Objective C Compiler +License: GPL-3.0+ +Group: Development/Languages +%description objc +This package contains the GNU Objective C compiler. Objective C is an +object oriented language, created by Next Inc. and used in their +Nextstep OS. The source code is available in the gcc package. + +%package -n libobjc +Summary: Library for the GNU Objective C Compiler +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libobjc +The library for the GNU Objective C compiler. +%post -n libobjc -p /sbin/ldconfig +%postun -n libobjc -p /sbin/ldconfig + +%package -n libcc1 +Summary: GNU C Compiler plugin for GDB +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libcc1 +The GCC plugin for GDB +%post -n libcc1 -p /sbin/ldconfig +%postun -n libcc1 -p /sbin/ldconfig + +%package obj-c++ +Summary: GNU Objective C++ Compiler +License: GPL-3.0+ +Group: Development/Languages +%description obj-c++ +This package contains the GNU Objective C++ compiler. Objective C++ is an +object oriented language, created by Next Inc. and used in their +Nextstep OS. The source code is available in the gcc package. + +%package -n cpp +Summary: The GCC Preprocessor +License: GPL-3.0+ +Group: Development/Languages +%description -n cpp +This Package contains just the preprocessor that is used by the X11 +packages. + +%package ada +Summary: GNU Ada95 Compiler Based on GCC (GNAT) +License: GPL-3.0+ +Group: Development/Languages +%description ada +This package contains an Ada95 compiler and associated development +tools based on the GNU GCC technology. Ada95 is the object oriented +successor of the Ada83 language. To build this package from source you +must have installed a binary version to bootstrap the compiler. + +%package -n libada +Summary: GNU Ada Runtime Libraries +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libada +This package contains the shared libraries required to run programs +compiled with the GNU Ada compiler (GNAT) if they are compiled to use +shared libraries. It also contains the shared libraries for the +Implementation of the Ada Semantic Interface Specification (ASIS), the +implementation of Distributed Systems Programming (GLADE) and the Posix +1003.5 Binding (Florist). +%post -n libada -p /sbin/ldconfig +%postun -n libada -p /sbin/ldconfig + +%package fortran +Summary: The GNU Fortran Compiler and Support Files +License: GPL-3.0+ +Group: Development/Languages +%description fortran +This is the Fortran compiler of the GNU Compiler Collection (GCC). + +%package -n libgfortran +Summary: The GNU Fortran Compiler Runtime Library +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libgfortran +The runtime library needed to run programs compiled with the Fortran compiler +of the GNU Compiler Collection (GCC). +%post -n libgfortran -p /sbin/ldconfig +%postun -n libgfortran -p /sbin/ldconfig + +%package -n libquadmath +Summary: The GNU Fortran Compiler Quadmath Runtime Library +License: LGPL-2.1 +Group: Development/Languages +%description -n libquadmath +The runtime library needed to run programs compiled with the Fortran compiler +of the GNU Compiler Collection (GCC) and quadruple precision floating point +operations. +%post -n libquadmath -p /sbin/ldconfig +%postun -n libquadmath -p /sbin/ldconfig + +%package -n libitm +Summary: The GNU Compiler Transactional Memory Runtime Library +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libitm +The runtime library needed to run programs compiled with the +-fgnu-tm option of the GNU Compiler Collection (GCC). +%post -n libitm -p /sbin/ldconfig +%postun -n libitm -p /sbin/ldconfig + +%package -n libasan +Summary: The GNU Compiler Address Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n libasan +The runtime library needed to run programs compiled with the +-fsanitize=address option of the GNU Compiler Collection (GCC). +%post -n libasan -p /sbin/ldconfig +%postun -n libasan -p /sbin/ldconfig + +%package -n libtsan +Summary: The GNU Compiler Thread Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n libtsan +The runtime library needed to run programs compiled with the +-fsanitize=thread option of the GNU Compiler Collection (GCC). +%post -n libtsan -p /sbin/ldconfig +%postun -n libtsan -p /sbin/ldconfig + +%package -n libatomic +Summary: The GNU Compiler Atomic Operations Runtime Library +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libatomic +The runtime library for atomic operations of the GNU Compiler Collection (GCC). +%post -n libatomic -p /sbin/ldconfig +%postun -n libatomic -p /sbin/ldconfig + +%package -n libcilkrts +Summary: The GNU Compiler Cilk+ Runtime Library +License: MIT +Group: Development/Languages +%description -n libcilkrts +The runtime library needed to run programs compiled with the +-fcilkplus option of the GNU Compiler Collection (GCC). +%post -n libcilkrts -p /sbin/ldconfig +%postun -n libcilkrts -p /sbin/ldconfig + +%package -n liblsan +Summary: The GNU Compiler Leak Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n liblsan +The runtime library needed to run programs compiled with the +-fsanitize=leak option of the GNU Compiler Collection (GCC). +%post -n liblsan -p /sbin/ldconfig +%postun -n liblsan -p /sbin/ldconfig + +%package -n libubsan +Summary: The GNU Compiler Undefined Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n libubsan +The runtime library needed to run programs compiled with the +-fsanitize=undefined option of the GNU Compiler Collection (GCC). +%post -n libubsan -p /sbin/ldconfig +%postun -n libubsan -p /sbin/ldconfig + +%package -n libvtv +Summary: The GNU Compiler Vtable Verifier Runtime Library +License: MIT +Group: Development/Languages +%description -n libvtv +The runtime library needed to run programs compiled with the +-fvtable-verify option of the GNU Compiler Collection (GCC). +%post -n libvtv -p /sbin/ldconfig +%postun -n libvtv -p /sbin/ldconfig + +%package -n libgcj +Summary: Java Runtime Library for gcc +License: GPL-2.0-with-classpath-exception +Group: Development/Building +%description -n libgcj +This library is needed if you want to use the GNU Java compiler, gcj. +Source code for this package is in gcc. +%post -n libgcj -p /sbin/ldconfig +%postun -n libgcj -p /sbin/ldconfig + +%package java +Summary: The GNU Java Compiler +License: GPL-3.0+ +Group: Development/Languages +%description java +The Java compiler from the GCC-tools-suite. + +%package -n libgcj_bc +Summary: Fake library for BC-ABI compatibility. +License: GPL-2.0-with-classpath-exception +Group: Development/Languages +%description -n libgcj_bc +A fake library that is used at link time only. It ensures that +binaries built with the BC-ABI link against a constant SONAME. +This way, BC-ABI binaries continue to work if the SONAME underlying +libgcj.so changes. + +%package -n libgcj-jar +Summary: Java runtime library (jar files). +License: GPL-2.0-with-classpath-exception +Group: Development/Languages +%description -n libgcj-jar +These are the jar files that go along with the gcj front end to gcc. + +%package -n libgcj-devel +Summary: Include Files and Libraries mandatory for Development. +License: GPL-2.0-with-classpath-exception +Group: Development/Languages +%description -n libgcj-devel +This package contains all necessary include files and libraries needed +to develop applications that require these. + +%package -n gcc-gij +Summary: Java Bytecode Interpreter for gcc +License: GPL-2.0-with-classpath-exception +Group: Development/Languages +%description -n gcc-gij +This package contains the java bytecode interpreter gij and related tools. + +%package -n libffi +Summary: Foreign Function Interface library +License: BSD-3-Clause +Group: Development/Building +%description -n libffi +A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. +%post -n libffi -p /sbin/ldconfig +%postun -n libffi -p /sbin/ldconfig + +%package -n libffi-devel +Summary: Foreign Function Interface library development files +License: BSD 3-Clause +Group: Development/Building +%description -n libffi-devel +A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. + +%package go +Summary: GNU Go Compiler +License: GPL-3.0+ +Group: Development/Languages +%description go +This package contains a Go compiler and associated development +files based on the GNU GCC technology. + +%package -n libgo +Summary: GNU Go compiler runtime library +License: BSD-3-Clause +Group: Development/Languages +%description -n libgo +A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. +%post -n libgo -p /sbin/ldconfig +%postun -n libgo -p /sbin/ldconfig + +%package testresults +Summary: Testsuite results +License: SUSE-Public-Domain +Group: Development/Languages +%description testresults +Results from running the gcc and target library testsuites. + +%package -n gcc-32bit +Summary: The GNU C Compiler 32bit support +Group: Development/Building +%description -n gcc-32bit +This package contains 32bit support for the GNU Compiler Collection. + +%package -n libstdc++-devel-32bit +Summary: Include Files and Libraries mandatory for Development +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libstdc++-devel-32bit +This package contains all the headers and libraries of the standard C++ +library. It is needed for compiling C++ code. + +%package -n libgcc-32bit +Summary: C compiler runtime library +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libgcc-32bit +Libgcc is needed for dynamically linked C programs. +%post -n libgcc-32bit -p /sbin/ldconfig +%postun -n libgcc-32bit -p /sbin/ldconfig + +%package -n libgomp-32bit +Summary: The GNU compiler collection OpenMP runtime library +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libgomp-32bit +This is the OpenMP runtime library needed by OpenMP enabled programs +that were built with the -fopenmp compiler option and by programs that +were auto-parallelized via the -ftree-parallelize-loops compiler +option. +%post -n libgomp-32bit -p /sbin/ldconfig +%postun -n libgomp-32bit -p /sbin/ldconfig + +%package -n libstdc++-32bit +Summary: The standard C++ shared library +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libstdc++-32bit +The standard C++ library, needed for dynamically linked C++ programs. +%post -n libstdc++-32bit -p /sbin/ldconfig +%postun -n libstdc++-32bit -p /sbin/ldconfig + +%package objc-32bit +Summary: GNU Objective C Compiler +License: GPL-3.0+ +Group: Development/Languages +%description objc-32bit +This package contains the GNU Objective C compiler. Objective C is an +object oriented language, created by Next Inc. and used in their +Nextstep OS. The source code is available in the gcc package. + +%package -n libobjc-32bit +Summary: Library for the GNU Objective C Compiler +License: GPL-3.0-with-GCC-exception +Group: Development/Building +%description -n libobjc-32bit +The library for the GNU Objective C compiler. +%post -n libobjc-32bit -p /sbin/ldconfig +%postun -n libobjc-32bit -p /sbin/ldconfig + +%package ada-32bit +Summary: GNU Ada95 Compiler Based on GCC (GNAT) +License: GPL-3.0+ +Group: Development/Languages +%description ada-32bit +This package contains an Ada95 compiler and associated development +tools based on the GNU GCC technology. Ada95 is the object oriented +successor of the Ada83 language. To build this package from source you +must have installed a binary version to bootstrap the compiler. + +%package -n libada-32bit +Summary: GNU Ada Runtime Libraries +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libada-32bit +This package contains the shared libraries required to run programs +compiled with the GNU Ada compiler (GNAT) if they are compiled to use +shared libraries. It also contains the shared libraries for the +Implementation of the Ada Semantic Interface Specification (ASIS), the +implementation of Distributed Systems Programming (GLADE) and the Posix +1003.5 Binding (Florist). +%post -n libada-32bit -p /sbin/ldconfig +%postun -n libada-32bit -p /sbin/ldconfig + +%package fortran-32bit +Summary: The GNU Fortran Compiler and Support Files +License: GPL-3.0+ +Group: Development/Languages +%description fortran-32bit +This is the Fortran compiler of the GNU Compiler Collection (GCC). + +%package -n libgfortran-32bit +Summary: The GNU Fortran Compiler Runtime Library +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libgfortran-32bit +The runtime library needed to run programs compiled with the Fortran compiler +of the GNU Compiler Collection (GCC). +%post -n libgfortran-32bit -p /sbin/ldconfig +%postun -n libgfortran-32bit -p /sbin/ldconfig + +%package -n libquadmath-32bit +Summary: The GNU Fortran Compiler Quadmath Runtime Library +License: LGPL-2.1 +Group: Development/Languages +%description -n libquadmath-32bit +The runtime library needed to run programs compiled with the Fortran compiler +of the GNU Compiler Collection (GCC) and quadruple precision floating point +operations. +%post -n libquadmath-32bit -p /sbin/ldconfig +%postun -n libquadmath-32bit -p /sbin/ldconfig + +%package -n libitm-32bit +Summary: The GNU Compiler Transactional Memory Runtime Library +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libitm-32bit +The runtime library needed to run programs compiled with the +-fgnu-tm option of the GNU Compiler Collection (GCC). +%post -n libitm-32bit -p /sbin/ldconfig +%postun -n libitm-32bit -p /sbin/ldconfig + +%package -n libasan-32bit +Summary: The GNU Compiler Address Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n libasan-32bit +The runtime library needed to run programs compiled with the +-fsanitize=address option of the GNU Compiler Collection (GCC). +%post -n libasan-32bit -p /sbin/ldconfig +%postun -n libasan-32bit -p /sbin/ldconfig + +%package -n liblsan-32bit +Summary: The GNU Compiler Address Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n liblsan-32bit +The runtime library needed to run programs compiled with the +-fsanitize=leak option of the GNU Compiler Collection (GCC). +%post -n liblsan-32bit -p /sbin/ldconfig +%postun -n liblsan-32bit -p /sbin/ldconfig + +%package -n libtsan-32bit +Summary: The GNU Compiler Thread Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n libtsan-32bit +The runtime library needed to run programs compiled with the +-fsanitize=thread option of the GNU Compiler Collection (GCC). +%post -n libtsan-32bit -p /sbin/ldconfig +%postun -n libtsan-32bit -p /sbin/ldconfig + +%package -n libatomic-32bit +Summary: The GNU Compiler Atomic Operations Runtime Library +License: GPL-3.0-with-GCC-exception +Group: Development/Languages +%description -n libatomic-32bit +The runtime library for atomic operations of the GNU Compiler Collection (GCC). +%post -n libatomic-32bit -p /sbin/ldconfig +%postun -n libatomic-32bit -p /sbin/ldconfig + +%package -n libcilkrts-32bit +Summary: The GNU Compiler Cilk+ Runtime Library +License: MIT +Group: Development/Languages +%description -n libcilkrts-32bit +The runtime library needed to run programs compiled with the +-fcilkplus option of the GNU Compiler Collection (GCC). +%post -n libcilkrts-32bit -p /sbin/ldconfig +%postun -n libcilkrts-32bit -p /sbin/ldconfig + +%package -n libubsan-32bit +Summary: The GNU Compiler Undefined Sanitizer Runtime Library +License: MIT +Group: Development/Languages +%description -n libubsan-32bit +The runtime library needed to run programs compiled with the +-fsanitize=undefined option of the GNU Compiler Collection (GCC). +%post -n libubsan-32bit -p /sbin/ldconfig +%postun -n libubsan-32bit -p /sbin/ldconfig + +%package -n libvtv-32bit +Summary: The GNU Compiler Vtable Verifier Runtime Library +License: MIT +Group: Development/Languages +%description -n libvtv-32bit +The runtime library needed to run programs compiled with the +-fvtable-verify option of the GNU Compiler Collection (GCC). +%post -n libvtv-32bit -p /sbin/ldconfig +%postun -n libvtv-32bit -p /sbin/ldconfig + +%package -n libffi-32bit +Summary: Foreign Function Interface library +License: BSD-3-Clause +Group: Development/Building +%description -n libffi-32bit +A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. +%post -n libffi-32bit -p /sbin/ldconfig +%postun -n libffi-32bit -p /sbin/ldconfig + +%package -n libffi-devel-32bit +Summary: Foreign Function Interface library development files +License: BSD 3-Clause +Group: Development/Building +%description -n libffi-devel-32bit +A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. + +%package go-32bit +Summary: GNU Go Compiler +License: GPL-3.0+ +Group: Development/Languages +%description go-32bit +This package contains a Go compiler and associated development +files based on the GNU GCC technology. + +%package -n libgo-32bit +Summary: GNU Go compiler runtime library +License: BSD-3-Clause +Group: Development/Languages +%description -n libgo-32bit +A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. +%post -n libgo-32bit -p /sbin/ldconfig +%postun -n libgo-32bit -p /sbin/ldconfig + +%package plugin-devel +Summary: GNU GCC Plugin development files +License: GPL-3.0+ +Group: Development/Languages +%description plugin-devel +This package contains GCC Plugin development files needed for compiler +plugins build. + +%package -n sanitizer-sources +Summary: Sanitizer family tools sources +License: MIT +Group: Development/Tools +BuildArch: noarch + +%description -n sanitizer-sources +Sanitizer family tools sources for external tools. + +%prep + +%setup -q -n gcc-%{version} +cp %{SOURCE20} . + +tar xf %{SOURCE10} +ln -sf gmp-6.1.1 gmp +tar xf %{SOURCE11} +ln -sf mpfr-3.1.5 mpfr +tar xf %{SOURCE12} +ln -sf mpc-1.0.3 mpc +tar xf %{SOURCE13} +ln -sf isl-0.17.1 isl + +echo "" > gcc/DEV-PHASE + +%global gcc_release `sed -e 's/^.*-//g' %{_builddir}/gcc-%{version}/gcc/LINARO-VERSION` + +%build +%{?asan:%gcc_unforce_options} +rm -rf obj +mkdir obj +cd obj + +RPM_OPT_FLAGS=`echo $RPM_OPT_FLAGS|sed -e 's/-fno-rtti//g' -e 's/-fno-exceptions//g' -e 's/-Wmissing-format-attribute//g' -e 's/-fstack-protector//g' -e 's/-ffortify=.//g' -e 's/-Wall//g' -e 's/-m32//g' -e 's/-m64//g' -e 's/-fexceptions//' -e 's/\([[:space:]]\+.*-D_FORTIFY_SOURCE=\)[[:alnum:]]\+/\10/g' +RPM_OPT_FLAGS="$RPM_OPT_FLAGS -D__USE_FORTIFY_LEVEL=0"` +%{?cross: +RPM_OPT_FLAGS=`echo $RPM_OPT_FLAGS|sed -e 's/-m\(arch\|tune\|cpu\)=[^ ]*//g'` +RPM_OPT_FLAGS=`echo $RPM_OPT_FLAGS|sed -e 's/-m\(sse\|fpmath\)[^ ]*//g'` +} +RPM_OPT_FLAGS=`echo $RPM_OPT_FLAGS|sed -e 's/ */ /g'` + + + +CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" XCFLAGS="$RPM_OPT_FLAGS" \ +TCFLAGS="$RPM_OPT_FLAGS" GCJFLAGS="$RPM_OPT_FLAGS" \ +../configure \ + --prefix=%{_prefix} \ + --infodir=%{_infodir} \ + --mandir=%{_mandir} \ + --libdir=%{libdir} \ + --libexecdir=%{libdir} \ + --enable-languages=c,c++,fortran \ + --enable-checking=release \ + --disable-libssp \ + --disable-bootstrap \ + --disable-libvtv \ + --enable-plugin \ + --disable-libcc1 \ + --disable-libgcj \ + --with-slibdir=%{libdir} \ + --with-system-zlib \ + --with-sysroot=/ \ + --enable-__cxa_atexit \ + --enable-libstdcxx-allocator=new \ + --enable-version-specific-runtime-libs \ + --enable-linker-build-id \ + --without-system-libunwind \ + --enable-threads=posix \ + --disable-multilib \ + --enable-lto \ +%{!?cross: \ + --enable-libcc1 \ + --enable-libgfortran \ + %{?asanbootstrap:--enable-bootstrap --with-build-config=bootstrap-asan} \ +%ifarch armv7l + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ +%endif +%ifarch armv7hl + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +%endif +%ifarch aarch64 + --with-arch=armv8-a \ + --disable-sjlj-exceptions \ +%endif +%ifarch %ix86 + --with-arch-32=i586 \ + --with-tune=generic \ + --disable-libmpx \ +%endif +%ifarch x86_64 + --with-arch-32=i586 \ + --with-tune=generic \ + --enable-multilib \ + --disable-libmpx \ +%endif +} \ +%{?cross: \ +%{?armv7l: \ + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ +} \ +%{?armv7hl: \ + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +} \ +%{?aarch64: \ + --with-arch=armv8-a \ + --disable-sjlj-exceptions \ +} \ + --disable-libgcc \ + --disable-libgfortran \ + --disable-libquadmath \ + --disable-libgomp \ + --disable-libatomic \ + --disable-libstdc++-v3 \ + --disable-libsanitizer \ + --disable-libitm \ +} \ + --with-bugurl="http://bugs.tizen.org/" \ + --with-pkgversion="Tizen/Linaro GCC %{version} %{gcc_release}" \ + --target=%{target_arch} \ + --host=%{host_arch} \ + --build=%{host_arch} + +make BOOT_CFLAGS="$RPM_OPT_FLAGS" %{?_smp_mflags} +%{?gcc_run_tests: + echo "Run testsuite" + # asan needs a whole shadow address space + ulimit -v unlimited || true + make -k check %{?_smp_mflags} || true + mkdir ../testresults + ../contrib/test_summary | tee ../testresults/test_summary.txt +} + +%install +cd obj + +make install DESTDIR=$RPM_BUILD_ROOT + +%{?gcc_run_tests: + cp `find . -name "*.sum"` ../testresults/ + cp `find . -name "*.log" \! -name "config.log" | grep -v 'acats.\?/tests' ` ../testresults/ + chmod 644 ../testresults/* +} + +%{remove_docs} +rm -rf %{buildroot}/%{_datadir}/locale + +#remove everything we don't need +rm -rf %{buildroot}/%{libsubdir}/install-tools +find %{buildroot}/ -name "*.la" -delete + +%{!?cross: +ln -s gcc %{buildroot}%{_bindir}/cc +mv %{buildroot}%{libsubdir}/libstdc++.so*-gdb.py %{buildroot}%{_datadir}/gcc-%{version}/python/libstdcxx/ + +# expose plugins for ar (required for lto builds) +mkdir -p %{buildroot}%{_prefix}/lib/bfd-plugins +ln -sf %{libsubdir}/liblto_plugin.so %{buildroot}%{_prefix}/lib/bfd-plugins/liblto_plugin.so + +# legacy preprocessor +mkdir -p %{buildroot}/lib +ln -s %{_bindir}/cpp %{buildroot}/lib/cpp + +# 32-bit libgcc in multilib configuration +%ifarch x86_64 +mv %{buildroot}%{_prefix}/lib/libgcc_s.so* %{buildroot}%{libsubdir}/32/ +%endif + +# move libraries to libdir +for lib in asan atomic cilkrts gfortran gomp cc1 itm lsan quadmath stdc++ supc++ tsan ubsan +do + [ -e %{buildroot}%{libsubdir}/lib$lib.a ] && mv %{buildroot}%{libsubdir}/lib$lib.a %{buildroot}%{libdir}/ + [ -e %{buildroot}%{libsubdir}/lib$lib.so ] && mv %{buildroot}%{libsubdir}/lib$lib.so* %{buildroot}%{libdir}/ +done +} + +%{?cross: +rm -rf %{buildroot}/%{libsubdir}/include-fixed +rm -rf %{buildroot}/%{libsubdir}/include +} + +%{!?cross: +cd ../ +tar -czf libsanitizer.tar.bz libsanitizer +mkdir -p %{buildroot}/src +mv -v libsanitizer.tar.bz %{buildroot}/src +} + +%files +%manifest gcc.manifest +%defattr(-,root,root) +%{?cross: +%{_bindir}/* +%{libsubdir}/* +} +%{!?cross: +%{_bindir}/gcc +%{_bindir}/cc +%{_bindir}/gcov +%{_bindir}/gcov-tool +%{_bindir}/gcc-ar +%{_bindir}/gcc-nm +%{_bindir}/gcc-ranlib +%{_bindir}/%{target_arch}-gcc +%{_bindir}/%{target_arch}-gcc-%{version} +%{_bindir}/%{target_arch}-gcc-ar +%{_bindir}/%{target_arch}-gcc-nm +%{_bindir}/%{target_arch}-gcc-ranlib +%{libsubdir}/collect2 +%{libsubdir}/lto1 +%{libsubdir}/lto-wrapper +%{libsubdir}/liblto_plugin.so* +%{_prefix}/lib/bfd-plugins/liblto_plugin.so +%{libsubdir}/include-fixed/* +%{libsubdir}/include/*.h +%{libsubdir}/*.a +%{libsubdir}/*.so +%{libsubdir}/*.o +%{libsubdir}/*.spec +%{libdir}/*.so +%{libdir}/*.a +%ifarch %cilkrts_arch +%{libsubdir}/include/cilk/* +%endif +%{libsubdir}/include/sanitizer/* +%ifarch %asan_arch +%exclude %{libdir}/libasan.so +%endif +%ifarch %lsan_arch +%exclude %{libdir}/liblsan.so +%endif +%ifarch %tsan_arch +%exclude %{libdir}/libtsan.so +%endif + +%files c++ +%defattr(-,root,root) +%{libsubdir}/cc1plus +%{_bindir}/g++ +%{_bindir}/c++ +%{_bindir}/%{target_arch}-g++ +%{_bindir}/%{target_arch}-c++ + +%files -n libstdc++ +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libdir}/libstdc++.so.* + +%files -n libstdc++-devel +%defattr(-,root,root) +%{libdir}/libstdc++.so +%{libdir}/libstdc++.a +%{libdir}/libsupc++.a +%{libsubdir}/include/c++/* +%{_datadir}/gcc-%{version}/python/libstdcxx/* + +%files -n libgcc +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libdir}/libgcc_s.so.* + +%files -n libgomp +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libdir}/libgomp.so.* + +%files -n libcc1 +%manifest gcc.manifest +%defattr(-,root,root) +%{libdir}/libcc1.so.* + +%ifarch %asan_arch +%files -n libasan +%manifest gcc.manifest +%license libsanitizer/LICENSE.TXT +%defattr(-,root,root) +%{libdir}/libasan.so* +%endif + +%ifarch %lsan_arch +%files -n liblsan +%manifest gcc.manifest +%license libsanitizer/LICENSE.TXT +%defattr(-,root,root) +%{libdir}/liblsan.so* +%endif + +%ifarch %tsan_arch +%files -n libtsan +%manifest gcc.manifest +%license libsanitizer/LICENSE.TXT +%defattr(-,root,root) +%{libdir}/libtsan.so* +%endif + +%ifarch %atomic_arch +%files -n libatomic +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libdir}/libatomic.so.* +%endif + +%ifarch %itm_arch +%files -n libitm +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libdir}/libitm.so.* +%endif + +%ifarch %cilkrts_arch +%files -n libcilkrts +%manifest gcc.manifest +%defattr(-,root,root) +%{libdir}/libcilkrts.so.* +%endif + +%ifarch %ubsan_arch +%files -n libubsan +%manifest gcc.manifest +%license libsanitizer/LICENSE.TXT +%defattr(-,root,root) +%{libdir}/libubsan.so.* +%endif + +%files fortran +%defattr(-,root,root) +%dir %{libsubdir}/finclude +%{_bindir}/gfortran +%{_bindir}/%{target_arch}-gfortran +%{libsubdir}/f951 +%{libsubdir}/finclude/* +%{libdir}/libgfortran.a +%{libdir}/libgfortran.so +%{libsubdir}/libgfortran.spec +%{libsubdir}/libcaf_single.a +%ifarch %quadmath_arch +%{libdir}/libquadmath.a +%{libdir}/libquadmath.so +%endif + +%files -n libgfortran +%defattr(-,root,root) +%{libdir}/libgfortran.so.* + +%ifarch %quadmath_arch +%files -n libquadmath +%manifest gcc.manifest +%license COPYING.LIB +%defattr(-,root,root) +%{libdir}/libquadmath.so.* +%endif + +%files -n cpp +%defattr(-,root,root) +%{_bindir}/cpp +%{libsubdir}/cc1 +/lib/cpp + +%files plugin-devel +%defattr(-,root,root) +%{libsubdir}/plugin/* + +%{?gcc_run_tests: +%files testresults +%defattr(-,root,root) +%doc testresults/test_summary.txt +%doc testresults/*.sum +%doc testresults/*.log +} +%ifarch x86_64 +%files -n gcc-32bit +%defattr(-,root,root) +%{libsubdir}/32/crt* +%{libsubdir}/32/*.a +%{libsubdir}/32/*.so +%{libsubdir}/32/*.o +%{libsubdir}/32/*.spec + +%ifarch %asan_arch +%files -n libasan-32bit +%manifest gcc.manifest +%license libsanitizer/LICENSE.TXT +%defattr(-,root,root) +%{libsubdir}/32/libasan.so.* +%endif + +%ifarch %lsan_arch +%files -n liblsan-32bit +%manifest gcc.manifest +%license libsanitizer/LICENSE.TXT +%defattr(-,root,root) +%{libsubdir}/32/liblsan.so.* +%endif + +%ifarch %atomic_arch +%files -n libatomic-32bit +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libsubdir}/32/libatomic.so.* +%endif + +%ifarch %cilkrts_arch +%files -n libcilkrts-32bit +%defattr(-,root,root) +%{libsubdir}/32/libcilkrts.so.* +%endif + +%files -n libgcc-32bit +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libsubdir}/32/libgcc_s.so.* + +%files -n libgomp-32bit +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libsubdir}/32/libgomp.so.* + +%ifarch %itm_arch +%files -n libitm-32bit +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libsubdir}/32/libitm.so.* +%endif + +%files -n libgfortran-32bit +%defattr(-,root,root) +%dir %{libsubdir}/32/finclude +%{libsubdir}/32/libgfortran.so.* +%{libsubdir}/32/finclude/* + +%ifarch %quadmath_arch +%files -n libquadmath-32bit +%license COPYING.LIB +%defattr(-,root,root) +%{libsubdir}/32/libquadmath.so.* +%endif + +%ifarch %ubsan_arch +%files -n libubsan-32bit +%manifest gcc.manifest +%license libsanitizer/LICENSE.TXT +%defattr(-,root,root) +%{libsubdir}/32/libubsan.so.* +%endif + +%files -n libstdc++-32bit +%manifest gcc.manifest +%license COPYING3 COPYING.RUNTIME +%defattr(-,root,root) +%{libsubdir}/32/libstdc++.so.* +%exclude %{libsubdir}/32/libstdc++.so.*-gdb.py + +%files -n libstdc++-devel-32bit +%defattr(-,root,root) +%{libsubdir}/32/libstdc++.so.*-gdb.py +%endif + +%files -n sanitizer-sources +%defattr(-,root,root,-) +/src/libsanitizer.tar.bz + +} + +%changelog diff --git a/packaging/gcc-armv7l.spec b/packaging/gcc-armv7l.spec index 0d7655d..5bbfb4f 100644 --- a/packaging/gcc-armv7l.spec +++ b/packaging/gcc-armv7l.spec @@ -36,6 +36,10 @@ %define ARCH armv7l %define ABI eabi %endif +%ifarch armv7hl +%define ARCH armv7hl +%define ABI eabihf +%endif %ifarch %ix86 %define ARCH i586 %endif @@ -48,7 +52,7 @@ %define host_arch %{ARCH}-tizen-linux-gnu%{?ABI} %define target_cpu %{?cross}%{!?cross:%{ARCH}} -%define target_abi %{?cross:%{?armv7l:eabi}}%{!?cross:%{?ABI}} +%define target_abi %{?cross:%{?armv7l:eabi}%{?armv7hl:eabihf}}%{!?cross:%{?ABI}} %define target_arch %{target_cpu}-tizen-linux-gnu%{?target_abi} %define libdir %{!?cross:%{_libdir}}%{?cross:%{_prefix}/lib%{?aarch64:64}} @@ -714,6 +718,12 @@ TCFLAGS="$RPM_OPT_FLAGS" GCJFLAGS="$RPM_OPT_FLAGS" \ --with-tune=cortex-a8 \ --disable-sjlj-exceptions \ %endif +%ifarch armv7hl + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +%endif %ifarch aarch64 --with-arch=armv8-a \ --disable-sjlj-exceptions \ @@ -736,6 +746,12 @@ TCFLAGS="$RPM_OPT_FLAGS" GCJFLAGS="$RPM_OPT_FLAGS" \ --with-tune=cortex-a8 \ --disable-sjlj-exceptions \ } \ +%{?armv7hl: \ + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +} \ %{?aarch64: \ --with-arch=armv8-a \ --disable-sjlj-exceptions \ diff --git a/packaging/linaro-gcc.spec b/packaging/linaro-gcc.spec index fd937c3..5f2a0ba 100644 --- a/packaging/linaro-gcc.spec +++ b/packaging/linaro-gcc.spec @@ -33,6 +33,10 @@ %define ARCH armv7l %define ABI eabi %endif +%ifarch armv7hl +%define ARCH armv7hl +%define ABI eabihf +%endif %ifarch %ix86 %define ARCH i586 %endif @@ -45,7 +49,7 @@ %define host_arch %{ARCH}-tizen-linux-gnu%{?ABI} %define target_cpu %{?cross}%{!?cross:%{ARCH}} -%define target_abi %{?cross:%{?armv7l:eabi}}%{!?cross:%{?ABI}} +%define target_abi %{?cross:%{?armv7l:eabi}%{?armv7hl:eabihf}}%{!?cross:%{?ABI}} %define target_arch %{target_cpu}-tizen-linux-gnu%{?target_abi} %define libdir %{!?cross:%{_libdir}}%{?cross:%{_prefix}/lib%{?aarch64:64}} @@ -711,6 +715,12 @@ TCFLAGS="$RPM_OPT_FLAGS" GCJFLAGS="$RPM_OPT_FLAGS" \ --with-tune=cortex-a8 \ --disable-sjlj-exceptions \ %endif +%ifarch armv7hl + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +%endif %ifarch aarch64 --with-arch=armv8-a \ --disable-sjlj-exceptions \ @@ -733,6 +743,12 @@ TCFLAGS="$RPM_OPT_FLAGS" GCJFLAGS="$RPM_OPT_FLAGS" \ --with-tune=cortex-a8 \ --disable-sjlj-exceptions \ } \ +%{?armv7hl: \ + --with-arch=armv7-a \ + --with-tune=cortex-a8 \ + --disable-sjlj-exceptions \ + --with-float=hard \ +} \ %{?aarch64: \ --with-arch=armv8-a \ --disable-sjlj-exceptions \ diff --git a/packaging/pre_checkin.sh b/packaging/pre_checkin.sh index 8442294..2ab1f12 100755 --- a/packaging/pre_checkin.sh +++ b/packaging/pre_checkin.sh @@ -1,7 +1,7 @@ #!/bin/bash # the script takes linaro-gcc.spec and creates the gcc-* packages -for arch in armv7l aarch64; do +for arch in armv7l armv7hl aarch64; do echo -n "Building package for $arch --> gcc-$arch ..." -- 2.7.4 From 60af37c3341505774d6aec59def8c2fa284e10d7 Mon Sep 17 00:00:00 2001 From: Slava Barinov Date: Thu, 14 Sep 2017 12:42:17 +0300 Subject: [PATCH 07/16] [TTC-9] Make LSan compliant with recovery mode when running on top of ASan Don't overwrite exit code in LSan when running on top of ASan in recovery mode to avoid breakage of users code due to found leaks. Change-Id: I172f59734837d3df350c9e586ace2547ae9f3f23 Signed-off-by: Slava Barinov --- ChangeLog.Tizen | 7 +++++++ gcc/testsuite/gcc.dg/asan/leak_recover-1.c | 16 ++++++++++++++++ gcc/testsuite/gcc.dg/asan/leak_recover-2.c | 17 +++++++++++++++++ libsanitizer/asan/asan_rtl.cc | 5 ++++- libsanitizer/lsan/lsan_common.cc | 5 +++++ libsanitizer/lsan/lsan_common.h | 1 + 6 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/asan/leak_recover-1.c create mode 100644 gcc/testsuite/gcc.dg/asan/leak_recover-2.c diff --git a/ChangeLog.Tizen b/ChangeLog.Tizen index f1ebf58..df9eeca 100644 --- a/ChangeLog.Tizen +++ b/ChangeLog.Tizen @@ -29,6 +29,13 @@ # log at the same time (actually you can't). However, if you update this # file after the commit hash is fixed, you are free to add the commit hash. ################################################################################ +2017-10-20 Slava Barinov + + [TTC-9] Enable recovery mode for ASan with leak detector + +2017-10-17 Mikhail Kashkarov + + Add armv7hl support. 2017-09-26 Dongkyun Son diff --git a/gcc/testsuite/gcc.dg/asan/leak_recover-1.c b/gcc/testsuite/gcc.dg/asan/leak_recover-1.c new file mode 100644 index 0000000..a17a72b --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/leak_recover-1.c @@ -0,0 +1,16 @@ +/* { dg-do run } */ +/* { dg-set-target-env-var ASAN_OPTIONS "halt_on_error=0" } */ + +#include + +int f () { + volatile int* a = malloc(20); + a[0] = 1; + return a[0]; +} + +int main() { + f(); +} + +/* { dg-output {Direct leak of 20 byte} } */ diff --git a/gcc/testsuite/gcc.dg/asan/leak_recover-2.c b/gcc/testsuite/gcc.dg/asan/leak_recover-2.c new file mode 100644 index 0000000..1f57fb4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/leak_recover-2.c @@ -0,0 +1,17 @@ +/* { dg-do run } */ +/* { dg-set-target-env-var ASAN_OPTIONS "halt_on_error=1" } */ +/* { dg-shouldfail "asan" } */ + +#include + +int f () { + volatile int* a = malloc(20); + a[0] = 1; + return a[0]; +} + +int main() { + f(); +} + +/* { dg-output {Direct leak of 20 byte} } */ diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc index ba8cbb3..8b28e6a 100644 --- a/libsanitizer/asan/asan_rtl.cc +++ b/libsanitizer/asan/asan_rtl.cc @@ -595,7 +595,10 @@ static void AsanInitInternal() { if (CAN_SANITIZE_LEAKS) { __lsan::InitCommonLsan(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) { - Atexit(__lsan::DoLeakCheck); + if (flags()->halt_on_error) + Atexit(__lsan::DoLeakCheck); + else + Atexit(__lsan::DoRecoverableLeakCheckVoid); } } diff --git a/libsanitizer/lsan/lsan_common.cc b/libsanitizer/lsan/lsan_common.cc index 670eb60..3808f2b 100644 --- a/libsanitizer/lsan/lsan_common.cc +++ b/libsanitizer/lsan/lsan_common.cc @@ -509,6 +509,10 @@ static int DoRecoverableLeakCheck() { return have_leaks ? 1 : 0; } +void DoRecoverableLeakCheckVoid() { + DoRecoverableLeakCheck(); +} + static Suppression *GetSuppressionForAddr(uptr addr) { Suppression *s = nullptr; @@ -671,6 +675,7 @@ uptr LeakReport::UnsuppressedLeakCount() { namespace __lsan { void InitCommonLsan() { } void DoLeakCheck() { } +void DoRecoverableLeakCheckVoid() { } void DisableInThisThread() { } void EnableInThisThread() { } } diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h index 53cd1c6..85b76db 100644 --- a/libsanitizer/lsan/lsan_common.h +++ b/libsanitizer/lsan/lsan_common.h @@ -117,6 +117,7 @@ enum IgnoreObjectResult { // Functions called from the parent tool. void InitCommonLsan(); void DoLeakCheck(); +void DoRecoverableLeakCheckVoid(); bool DisabledInThisThread(); // Used to implement __lsan::ScopedDisabler. -- 2.7.4 From 47e16e738a6ef562ee456b4051e314242a5edbae Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 13 Sep 2017 15:50:25 +0300 Subject: [PATCH 08/16] [TTC-8][Sanitizers] Secondary allocator respects allocator_may_return_null=1. Summary: Context: https://github.com/google/sanitizers/issues/740. Making secondary allocator to respect allocator_may_return_null=1 flag and return nullptr when "out of memory" happens. More changes in primary allocator and operator new will follow. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34243 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305569 91177308-0d34-0410-b5e6-96231b3b80d8 Change-Id: I534117600099ec8953a6d83c559da0cf3bdfb5ad --- .../sanitizer_common/sanitizer_allocator_secondary.h | 7 +++++-- libsanitizer/sanitizer_common/sanitizer_common.h | 3 +++ libsanitizer/sanitizer_common/sanitizer_posix.cc | 16 ++++++++++++++++ libsanitizer/sanitizer_common/sanitizer_win.cc | 10 ++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h index 91c2ecc..60a3e03 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h @@ -34,9 +34,12 @@ class LargeMmapAllocator { if (alignment > page_size_) map_size += alignment; // Overflow. - if (map_size < size) return ReturnNullOrDieOnBadRequest(); + if (map_size < size) + return ReturnNullOrDieOnBadRequest(); uptr map_beg = reinterpret_cast( - MmapOrDie(map_size, "LargeMmapAllocator")); + MmapOrDieOnFatalError(map_size, "LargeMmapAllocator")); + if (!map_beg) + return ReturnNullOrDieOnOOM(); CHECK(IsAligned(map_beg, page_size_)); MapUnmapCallback().OnMap(map_beg, map_size); uptr map_end = map_beg + map_size; diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index 3767a1c..ca91ddb 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -83,6 +83,9 @@ INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) { return MmapOrDie(size, mem_type, /*raw_report*/ true); } void UnmapOrDie(void *addr, uptr size); +// Behaves just like MmapOrDie, but tolerates out of memory condition, in that +// case returns nullptr. +void *MmapOrDieOnFatalError(uptr size, const char *mem_type); void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoReserveOrDie(uptr size, const char *mem_type); diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc index eccbdf6..2a03ce2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc @@ -20,6 +20,7 @@ #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" +#include #include #include #include @@ -144,6 +145,21 @@ void UnmapOrDie(void *addr, uptr size) { DecreaseTotalMmap(size); } +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + size = RoundUpTo(size, GetPageSizeCached()); + uptr res = internal_mmap(nullptr, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + int reserrno; + if (internal_iserror(res, &reserrno)) { + if (reserrno == ENOMEM) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); + } + IncreaseTotalMmap(size); + return (void *)res; +} + // We want to map a chunk of address space aligned to 'alignment'. // We do it by maping a bit more and then unmaping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc index 785883c..d16edbb 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_win.cc @@ -113,6 +113,16 @@ void UnmapOrDie(void *addr, uptr size) { } } +void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { + void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + if (rv == 0) { + error_t last_error = GetLastError(); + if (last_error != ERROR_NOT_ENOUGH_MEMORY) + ReportMmapFailureAndDie(size, mem_type, "allocate", last_error); + } + return rv; +} + // We want to map a chunk of address space aligned to 'alignment'. void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { CHECK(IsPowerOfTwo(size)); -- 2.7.4 From d053aec2b788f18e016369baaaf3a73c3c6ff7cb Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 13 Sep 2017 15:57:12 +0300 Subject: [PATCH 09/16] [TTC-8][Sanitizers] 32 bit allocator respects allocator_may_return_null flag Summary: Make SizeClassAllocator32 return nullptr when it encounters OOM, which allows the entire sanitizer's allocator to follow allocator_may_return_null=1 policy, even for small allocations (LargeMmapAllocator is already fixed by D34243). Will add a test for OOM in primary allocator later, when SizeClassAllocator64 can gracefully handle OOM too. Reviewers: eugenis Subscribers: kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34433 Change-Id: I2853a00cff5202189c5d4b15b1934c63d5206708 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@305972 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_local_cache.h | 17 ++++++++++++--- .../sanitizer_allocator_primary32.h | 21 ++++++++++++------ libsanitizer/sanitizer_common/sanitizer_common.h | 4 +++- libsanitizer/sanitizer_common/sanitizer_posix.cc | 7 ++++-- libsanitizer/sanitizer_common/sanitizer_win.cc | 25 +++++++++++++--------- 5 files changed, 52 insertions(+), 22 deletions(-) diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h index 40ef078..8d8eea9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h @@ -141,8 +141,10 @@ struct SizeClassAllocator32LocalCache { CHECK_LT(class_id, kNumClasses); stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; - if (UNLIKELY(c->count == 0)) - Refill(allocator, class_id); + if (UNLIKELY(c->count == 0)) { + if (UNLIKELY(!Refill(allocator, class_id))) + return nullptr; + } void *res = c->batch[--c->count]; PREFETCH(c->batch[c->count - 1]); return res; @@ -221,14 +223,17 @@ struct SizeClassAllocator32LocalCache { Deallocate(allocator, batch_class_id, b); } - NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) { + NOINLINE bool Refill(SizeClassAllocator *allocator, uptr class_id) { InitCache(); PerClass *c = &per_class_[class_id]; TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id); + if (UNLIKELY(!b)) + return false; CHECK_GT(b->Count(), 0); b->CopyToArray(c->batch); c->count = b->Count(); DestroyBatch(class_id, allocator, b); + return true; } NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) { @@ -238,6 +243,12 @@ struct SizeClassAllocator32LocalCache { uptr first_idx_to_drain = c->count - cnt; TransferBatch *b = CreateBatch( class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]); + // Failure to allocate a batch while releasing memory is non recoverable. + // TODO(alekseys): Figure out how to do it without allocating a new batch. + if (UNLIKELY(!b)) { + Printf("OOM happened\n"); + Die(); + } b->SetFromArray(allocator->GetRegionBeginBySizeClass(class_id), &c->batch[first_idx_to_drain], cnt); c->count -= cnt; diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h index e3ed896..dddd240 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h @@ -22,7 +22,8 @@ template struct SizeClassAllocator32LocalCache; // be returned by MmapOrDie(). // // Region: -// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize). +// a result of a single call to MmapAlignedOrDieOnFatalError(kRegionSize, +// kRegionSize). // Since the regions are aligned by kRegionSize, there are exactly // kNumPossibleRegions possible regions in the address space and so we keep // a ByteMap possible_regions to store the size classes of each Region. @@ -136,8 +137,9 @@ class SizeClassAllocator32 { CHECK_LT(class_id, kNumClasses); SizeClassInfo *sci = GetSizeClassInfo(class_id); SpinMutexLock l(&sci->mutex); - if (sci->free_list.empty()) - PopulateFreeList(stat, c, sci, class_id); + if (sci->free_list.empty() && + UNLIKELY(!PopulateFreeList(stat, c, sci, class_id))) + return nullptr; CHECK(!sci->free_list.empty()); TransferBatch *b = sci->free_list.front(); sci->free_list.pop_front(); @@ -268,8 +270,10 @@ class SizeClassAllocator32 { uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { CHECK_LT(class_id, kNumClasses); - uptr res = reinterpret_cast(MmapAlignedOrDie(kRegionSize, kRegionSize, - "SizeClassAllocator32")); + uptr res = reinterpret_cast(MmapAlignedOrDieOnFatalError( + kRegionSize, kRegionSize, "SizeClassAllocator32")); + if (UNLIKELY(!res)) + return 0; MapUnmapCallback().OnMap(res, kRegionSize); stat->Add(AllocatorStatMapped, kRegionSize); CHECK_EQ(0U, (res & (kRegionSize - 1))); @@ -282,16 +286,20 @@ class SizeClassAllocator32 { return &size_class_info_array[class_id]; } - void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, + bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, SizeClassInfo *sci, uptr class_id) { uptr size = ClassIdToSize(class_id); uptr reg = AllocateRegion(stat, class_id); + if (UNLIKELY(!reg)) + return false; uptr n_chunks = kRegionSize / (size + kMetadataSize); uptr max_count = TransferBatch::MaxCached(class_id); TransferBatch *b = nullptr; for (uptr i = reg; i < reg + n_chunks * size; i += size) { if (!b) { b = c->CreateBatch(class_id, this, (TransferBatch*)i); + if (!b) + return false; b->Clear(); } b->Add((void*)i); @@ -305,6 +313,7 @@ class SizeClassAllocator32 { CHECK_GT(b->Count(), 0); sci->free_list.push_back(b); } + return true; } ByteMap possible_regions; diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index ca91ddb..09234f7 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -93,7 +93,9 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size); void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoAccess(uptr size); // Map aligned chunk of address space; size and alignment are powers of two. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); +// Dies on all but out of memory errors, in the latter case returns nullptr. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type); // Disallow access to a memory range. Use MmapFixedNoAccess to allocate an // unaccessible memory. bool MprotectNoAccess(uptr addr, uptr size); diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc index 2a03ce2..aa35317 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc @@ -163,11 +163,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { // We want to map a chunk of address space aligned to 'alignment'. // We do it by maping a bit more and then unmaping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); uptr map_size = size + alignment; - uptr map_res = (uptr)MmapOrDie(map_size, mem_type); + uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); + if (!map_res) + return nullptr; uptr map_end = map_res + map_size; uptr res = map_res; if (res & (alignment - 1)) // Not aligned. diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc index d16edbb..6ff0a05 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_win.cc @@ -113,18 +113,24 @@ void UnmapOrDie(void *addr, uptr size) { } } +static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, + const char *mmap_type) { + error_t last_error = GetLastError(); + if (last_error == ERROR_NOT_ENOUGH_MEMORY) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); +} + void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (rv == 0) { - error_t last_error = GetLastError(); - if (last_error != ERROR_NOT_ENOUGH_MEMORY) - ReportMmapFailureAndDie(size, mem_type, "allocate", last_error); - } + if (rv == 0) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); return rv; } // We want to map a chunk of address space aligned to 'alignment'. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); @@ -134,7 +140,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { uptr mapped_addr = (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!mapped_addr) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); // If we got it right on the first try, return. Otherwise, unmap it and go to // the slow path. @@ -154,8 +160,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { mapped_addr = (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); if (!mapped_addr) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", - GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); // Find the aligned address. uptr aligned_addr = RoundUpTo(mapped_addr, alignment); @@ -173,7 +178,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { // Fail if we can't make this work quickly. if (retries == kMaxRetries && mapped_addr == 0) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); return (void *)mapped_addr; } -- 2.7.4 From 3fbeb464f7267fdfadc74ede9ce8473f823a5244 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Wed, 13 Sep 2017 16:22:49 +0300 Subject: [PATCH 10/16] [TTC-8][Sanitizers] 64 bit allocator respects allocator_may_return_null flag Summary: Make SizeClassAllocator64 return nullptr when it encounters OOM, which allows the entire sanitizer's allocator to follow allocator_may_return_null=1 policy (LargeMmapAllocator: D34243, SizeClassAllocator64: D34433). Reviewers: eugenis Subscribers: srhines, kubamracek, llvm-commits Differential Revision: https://reviews.llvm.org/D34540 Change-Id: I0e72b4b22a440eb644dcc370da0ba9aa0e71c2d5 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@306342 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../sanitizer_allocator_local_cache.h | 14 +- .../sanitizer_allocator_primary64.h | 187 +++++++++++++-------- libsanitizer/sanitizer_common/sanitizer_common.h | 3 + libsanitizer/sanitizer_common/sanitizer_posix.cc | 12 +- libsanitizer/sanitizer_common/sanitizer_win.cc | 12 ++ 5 files changed, 151 insertions(+), 77 deletions(-) diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h index 8d8eea9..f68f6ab 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h @@ -45,8 +45,10 @@ struct SizeClassAllocator64LocalCache { CHECK_LT(class_id, kNumClasses); stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id)); PerClass *c = &per_class_[class_id]; - if (UNLIKELY(c->count == 0)) - Refill(c, allocator, class_id); + if (UNLIKELY(c->count == 0)) { + if (UNLIKELY(!Refill(c, allocator, class_id))) + return nullptr; + } CHECK_GT(c->count, 0); CompactPtrT chunk = c->chunks[--c->count]; void *res = reinterpret_cast(allocator->CompactPtrToPointer( @@ -97,13 +99,15 @@ struct SizeClassAllocator64LocalCache { } } - NOINLINE void Refill(PerClass *c, SizeClassAllocator *allocator, + NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator, uptr class_id) { InitCache(); uptr num_requested_chunks = SizeClassMap::MaxCachedHint(class_id); - allocator->GetFromAllocator(&stats_, class_id, c->chunks, - num_requested_chunks); + if (UNLIKELY(!allocator->GetFromAllocator(&stats_, class_id, c->chunks, + num_requested_chunks))) + return false; c->count = num_requested_chunks; + return true; } NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, uptr class_id, diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h index 979e9d6..5afc856 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h @@ -77,17 +77,7 @@ class SizeClassAllocator64 { reinterpret_cast(MmapNoAccess(TotalSpaceSize)); CHECK_NE(NonConstSpaceBeg, ~(uptr)0); } - MapWithCallback(SpaceEnd(), AdditionalSize()); - } - - void MapWithCallback(uptr beg, uptr size) { - CHECK_EQ(beg, reinterpret_cast(MmapFixedOrDie(beg, size))); - MapUnmapCallback().OnMap(beg, size); - } - - void UnmapWithCallback(uptr beg, uptr size) { - MapUnmapCallback().OnUnmap(beg, size); - UnmapOrDie(reinterpret_cast(beg), size); + MapWithCallbackOrDie(SpaceEnd(), AdditionalSize()); } static bool CanAllocate(uptr size, uptr alignment) { @@ -105,13 +95,20 @@ class SizeClassAllocator64 { uptr old_num_chunks = region->num_freed_chunks; uptr new_num_freed_chunks = old_num_chunks + n_chunks; EnsureFreeArraySpace(region, region_beg, new_num_freed_chunks); + // Failure to allocate free array space while releasing memory is non + // recoverable. + if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, + new_num_freed_chunks))) { + Printf("OOM happened\n"); + Die(); + } for (uptr i = 0; i < n_chunks; i++) free_array[old_num_chunks + i] = chunks[i]; region->num_freed_chunks = new_num_freed_chunks; - region->n_freed += n_chunks; + region->stats.n_freed += n_chunks; } - NOINLINE void GetFromAllocator(AllocatorStats *stat, uptr class_id, + NOINLINE bool GetFromAllocator(AllocatorStats *stat, uptr class_id, CompactPtrT *chunks, uptr n_chunks) { RegionInfo *region = GetRegionInfo(class_id); uptr region_beg = GetRegionBeginBySizeClass(class_id); @@ -119,15 +116,17 @@ class SizeClassAllocator64 { BlockingMutexLock l(®ion->mutex); if (UNLIKELY(region->num_freed_chunks < n_chunks)) { - PopulateFreeArray(stat, class_id, region, - n_chunks - region->num_freed_chunks); + if (UNLIKELY(!PopulateFreeArray(stat, class_id, region, + n_chunks - region->num_freed_chunks))) + return false; CHECK_GE(region->num_freed_chunks, n_chunks); } region->num_freed_chunks -= n_chunks; uptr base_idx = region->num_freed_chunks; for (uptr i = 0; i < n_chunks; i++) chunks[i] = free_array[base_idx + i]; - region->n_allocated += n_chunks; + region->stats.n_allocated += n_chunks; + return true; } bool PointsIntoChunk(const void *p) { @@ -207,7 +206,7 @@ class SizeClassAllocator64 { // Test-only. void TestOnlyUnmap() { - UnmapWithCallback(SpaceBeg(), kSpaceSize + AdditionalSize()); + UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize()); } static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats, @@ -220,16 +219,16 @@ class SizeClassAllocator64 { void PrintStats(uptr class_id, uptr rss) { RegionInfo *region = GetRegionInfo(class_id); if (region->mapped_user == 0) return; - uptr in_use = region->n_allocated - region->n_freed; + uptr in_use = region->stats.n_allocated - region->stats.n_freed; uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id); Printf( - " %02zd (%zd): mapped: %zdK allocs: %zd frees: %zd inuse: %zd " + "%s %02zd (%zd): mapped: %zdK allocs: %zd frees: %zd inuse: %zd " "num_freed_chunks %zd" " avail: %zd rss: %zdK releases: %zd\n", - class_id, ClassIdToSize(class_id), region->mapped_user >> 10, - region->n_allocated, region->n_freed, in_use, - region->num_freed_chunks, avail_chunks, rss >> 10, - region->rtoi.num_releases); + region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id), + region->mapped_user >> 10, region->stats.n_allocated, + region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks, + rss >> 10, region->rtoi.num_releases); } void PrintStats() { @@ -239,8 +238,8 @@ class SizeClassAllocator64 { for (uptr class_id = 1; class_id < kNumClasses; class_id++) { RegionInfo *region = GetRegionInfo(class_id); total_mapped += region->mapped_user; - n_allocated += region->n_allocated; - n_freed += region->n_freed; + n_allocated += region->stats.n_allocated; + n_freed += region->stats.n_freed; } Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; " "remains %zd\n", @@ -328,6 +327,11 @@ class SizeClassAllocator64 { // Granularity of ReleaseToOs (aka madvise). static const uptr kReleaseToOsGranularity = 1 << 12; + struct Stats { + uptr n_allocated; + uptr n_freed; + }; + struct ReleaseToOsInfo { uptr n_freed_at_last_release; uptr num_releases; @@ -341,8 +345,9 @@ class SizeClassAllocator64 { uptr allocated_meta; // Bytes allocated for metadata. uptr mapped_user; // Bytes mapped for user memory. uptr mapped_meta; // Bytes mapped for metadata. - u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks. - uptr n_allocated, n_freed; // Just stats. + u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks. + bool exhausted; // Whether region is out of space for new chunks. + Stats stats; ReleaseToOsInfo rtoi; }; COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize); @@ -387,7 +392,26 @@ class SizeClassAllocator64 { kFreeArraySize); } - void EnsureFreeArraySpace(RegionInfo *region, uptr region_beg, + bool MapWithCallback(uptr beg, uptr size) { + uptr mapped = reinterpret_cast(MmapFixedOrDieOnFatalError(beg, size)); + if (!mapped) + return false; + CHECK_EQ(beg, mapped); + MapUnmapCallback().OnMap(beg, size); + return true; + } + + void MapWithCallbackOrDie(uptr beg, uptr size) { + CHECK_EQ(beg, reinterpret_cast(MmapFixedOrDie(beg, size))); + MapUnmapCallback().OnMap(beg, size); + } + + void UnmapWithCallbackOrDie(uptr beg, uptr size) { + MapUnmapCallback().OnUnmap(beg, size); + UnmapOrDie(reinterpret_cast(beg), size); + } + + bool EnsureFreeArraySpace(RegionInfo *region, uptr region_beg, uptr num_freed_chunks) { uptr needed_space = num_freed_chunks * sizeof(CompactPtrT); if (region->mapped_free_array < needed_space) { @@ -396,66 +420,87 @@ class SizeClassAllocator64 { uptr current_map_end = reinterpret_cast(GetFreeArray(region_beg)) + region->mapped_free_array; uptr new_map_size = new_mapped_free_array - region->mapped_free_array; - MapWithCallback(current_map_end, new_map_size); + if (UNLIKELY(!MapWithCallback(current_map_end, new_map_size))) + return false; region->mapped_free_array = new_mapped_free_array; } + return true; } - - NOINLINE void PopulateFreeArray(AllocatorStats *stat, uptr class_id, + NOINLINE bool PopulateFreeArray(AllocatorStats *stat, uptr class_id, RegionInfo *region, uptr requested_count) { // region->mutex is held. - uptr size = ClassIdToSize(class_id); - uptr beg_idx = region->allocated_user; - uptr end_idx = beg_idx + requested_count * size; - uptr region_beg = GetRegionBeginBySizeClass(class_id); - if (end_idx > region->mapped_user) { + const uptr size = ClassIdToSize(class_id); + const uptr new_space_beg = region->allocated_user; + const uptr new_space_end = new_space_beg + requested_count * size; + const uptr region_beg = GetRegionBeginBySizeClass(class_id); + + // Map more space for chunks, if necessary. + if (new_space_end > region->mapped_user) { if (!kUsingConstantSpaceBeg && region->mapped_user == 0) region->rand_state = static_cast(region_beg >> 12); // From ASLR. // Do the mmap for the user memory. uptr map_size = kUserMapSize; - while (end_idx > region->mapped_user + map_size) + while (new_space_end > region->mapped_user + map_size) map_size += kUserMapSize; - CHECK_GE(region->mapped_user + map_size, end_idx); - MapWithCallback(region_beg + region->mapped_user, map_size); + CHECK_GE(region->mapped_user + map_size, new_space_end); + if (UNLIKELY(!MapWithCallback(region_beg + region->mapped_user, + map_size))) + return false; stat->Add(AllocatorStatMapped, map_size); region->mapped_user += map_size; } - CompactPtrT *free_array = GetFreeArray(region_beg); - uptr total_count = (region->mapped_user - beg_idx) / size; - uptr num_freed_chunks = region->num_freed_chunks; - EnsureFreeArraySpace(region, region_beg, num_freed_chunks + total_count); - for (uptr i = 0; i < total_count; i++) { - uptr chunk = beg_idx + i * size; - free_array[num_freed_chunks + total_count - 1 - i] = - PointerToCompactPtr(0, chunk); + const uptr new_chunks_count = (region->mapped_user - new_space_beg) / size; + + // Calculate the required space for metadata. + const uptr requested_allocated_meta = + region->allocated_meta + new_chunks_count * kMetadataSize; + uptr requested_mapped_meta = region->mapped_meta; + while (requested_allocated_meta > requested_mapped_meta) + requested_mapped_meta += kMetaMapSize; + // Check whether this size class is exhausted. + if (region->mapped_user + requested_mapped_meta > + kRegionSize - kFreeArraySize) { + if (!region->exhausted) { + region->exhausted = true; + Printf("%s: Out of memory. ", SanitizerToolName); + Printf("The process has exhausted %zuMB for size class %zu.\n", + kRegionSize >> 20, size); + } + return false; } + // Map more space for metadata, if necessary. + if (requested_mapped_meta > region->mapped_meta) { + if (UNLIKELY(!MapWithCallback( + GetMetadataEnd(region_beg) - requested_mapped_meta, + requested_mapped_meta - region->mapped_meta))) + return false; + region->mapped_meta = requested_mapped_meta; + } + + // If necessary, allocate more space for the free array and populate it with + // newly allocated chunks. + const uptr total_freed_chunks = region->num_freed_chunks + new_chunks_count; + if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, total_freed_chunks))) + return false; + CompactPtrT *free_array = GetFreeArray(region_beg); + for (uptr i = 0, chunk = new_space_beg; i < new_chunks_count; + i++, chunk += size) + free_array[total_freed_chunks - 1 - i] = PointerToCompactPtr(0, chunk); if (kRandomShuffleChunks) - RandomShuffle(&free_array[num_freed_chunks], total_count, + RandomShuffle(&free_array[region->num_freed_chunks], new_chunks_count, ®ion->rand_state); - region->num_freed_chunks += total_count; - region->allocated_user += total_count * size; - CHECK_LE(region->allocated_user, region->mapped_user); - region->allocated_meta += total_count * kMetadataSize; - if (region->allocated_meta > region->mapped_meta) { - uptr map_size = kMetaMapSize; - while (region->allocated_meta > region->mapped_meta + map_size) - map_size += kMetaMapSize; - // Do the mmap for the metadata. - CHECK_GE(region->mapped_meta + map_size, region->allocated_meta); - MapWithCallback(GetMetadataEnd(region_beg) - - region->mapped_meta - map_size, map_size); - region->mapped_meta += map_size; - } + // All necessary memory is mapped and now it is safe to advance all + // 'allocated_*' counters. + region->num_freed_chunks += new_chunks_count; + region->allocated_user += new_chunks_count * size; + CHECK_LE(region->allocated_user, region->mapped_user); + region->allocated_meta = requested_allocated_meta; CHECK_LE(region->allocated_meta, region->mapped_meta); - if (region->mapped_user + region->mapped_meta > - kRegionSize - kFreeArraySize) { - Printf("%s: Out of memory. Dying. ", SanitizerToolName); - Printf("The process has exhausted %zuMB for size class %zu.\n", - kRegionSize / 1024 / 1024, size); - Die(); - } + region->exhausted = false; + + return true; } bool MaybeReleaseChunkRange(uptr region_beg, uptr chunk_size, @@ -489,7 +534,7 @@ class SizeClassAllocator64 { uptr n = region->num_freed_chunks; if (n * chunk_size < kReleaseToOsGranularity) return; // No chance to release anything. - if ((region->rtoi.n_freed_at_last_release - region->n_freed) * chunk_size < + if ((region->rtoi.n_freed_at_last_release - region->stats.n_freed) * chunk_size < kReleaseToOsGranularity) return; // Nothing new to release. SortArray(free_array, n); @@ -502,7 +547,7 @@ class SizeClassAllocator64 { CHECK_GT(chunk - prev, scaled_chunk_size); if (prev + scaled_chunk_size - beg >= kScaledGranularity) { MaybeReleaseChunkRange(region_beg, chunk_size, beg, prev); - region->rtoi.n_freed_at_last_release = region->n_freed; + region->rtoi.n_freed_at_last_release = region->stats.n_freed; region->rtoi.num_releases++; } beg = chunk; diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index 09234f7..592c5fc 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -90,6 +90,9 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoReserveOrDie(uptr size, const char *mem_type); void *MmapFixedOrDie(uptr fixed_addr, uptr size); +// Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in +// that case returns nullptr. +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size); void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr); void *MmapNoAccess(uptr size); // Map aligned chunk of address space; size and alignment are powers of two. diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc index aa35317..ed43d24 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc @@ -197,7 +197,7 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) { return (void *)p; } -void *MmapFixedOrDie(uptr fixed_addr, uptr size) { +void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem) { uptr PageSize = GetPageSizeCached(); uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)), RoundUpTo(size, PageSize), @@ -206,6 +206,8 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { -1, 0); int reserrno; if (internal_iserror(p, &reserrno)) { + if (tolerate_enomem && reserrno == ENOMEM) + return nullptr; char mem_type[30]; internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", fixed_addr); @@ -215,6 +217,14 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return (void *)p; } +void *MmapFixedOrDie(uptr fixed_addr, uptr size) { + return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/); +} + +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { + return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/); +} + bool MprotectNoAccess(uptr addr, uptr size) { return 0 == internal_mprotect((void*)addr, size, PROT_NONE); } diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc index 6ff0a05..7995c6e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_win.cc @@ -217,6 +217,18 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { return p; } +void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) { + void *p = VirtualAlloc((LPVOID)fixed_addr, size, + MEM_COMMIT, PAGE_READWRITE); + if (p == 0) { + char mem_type[30]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); + } + return p; +} + void *MmapNoReserveOrDie(uptr size, const char *mem_type) { // FIXME: make this really NoReserve? return MmapOrDie(size, mem_type); -- 2.7.4 From 7aa012c7872e8448c20f0794ca2fdfd0995220a7 Mon Sep 17 00:00:00 2001 From: Slava Barinov Date: Wed, 13 Sep 2017 18:13:49 +0300 Subject: [PATCH 11/16] [TTC-8][Sanitizers] Add tests for allocator_may_return_null=1 flag The LLVM test has been rewritten to be able to run inside GCC test suite. Change-Id: Ifaf9e3681ddacfaad73a314a01ab3c6c7704d40b Signed-off-by: Slava Barinov --- .../c-c++-common/asan/allocator_oom_test-1.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test-2.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test-3.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test-4.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test-5.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test-6.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test-7.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test-8.c | 16 ++++++ .../c-c++-common/asan/allocator_oom_test.inc | 58 ++++++++++++++++++++++ 9 files changed, 186 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-1.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-2.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-3.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-4.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-5.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-6.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-7.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test-8.c create mode 100644 gcc/testsuite/c-c++-common/asan/allocator_oom_test.inc diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-1.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-1.c new file mode 100644 index 0000000..e03c378 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-1.c @@ -0,0 +1,16 @@ +// Test the behavior of malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ + +#define ACTION "malloc" +#include "allocator_oom_test.inc" + +/* { dg-shouldfail "asan" } */ +/* { dg-output "malloc:\n==.*==AddressSanitizer's allocator is terminating the process" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-2.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-2.c new file mode 100644 index 0000000..4c6cb4d --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-2.c @@ -0,0 +1,16 @@ +// Test the behavior of malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ +/* { dg-set-target-env-var ASAN_OPTIONS "allocator_may_return_null=1" } */ + +#define ACTION "malloc" +#include "allocator_oom_test.inc" + +/* { dg-output "malloc:\nx: 0" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-3.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-3.c new file mode 100644 index 0000000..c470e47 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-3.c @@ -0,0 +1,16 @@ +// Test the behavior of malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ + +#define ACTION "realloc" +#include "allocator_oom_test.inc" + +/* { dg-shouldfail "asan" } */ +/* { dg-output "realloc:\n==.*==AddressSanitizer's allocator is terminating the process" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-4.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-4.c new file mode 100644 index 0000000..cc55a01 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-4.c @@ -0,0 +1,16 @@ +// Test the behavior of malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ +/* { dg-set-target-env-var ASAN_OPTIONS "allocator_may_return_null=1" } */ + +#define ACTION "realloc" +#include "allocator_oom_test.inc" + +/* { dg-output "realloc:\nx: 0" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-5.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-5.c new file mode 100644 index 0000000..3c1788a --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-5.c @@ -0,0 +1,16 @@ +// Test the behavior of calloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ + +#define ACTION "calloc" +#include "allocator_oom_test.inc" + +/* { dg-shouldfail "asan" } */ +/* { dg-output "calloc:\n==.*==AddressSanitizer's allocator is terminating the process" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-6.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-6.c new file mode 100644 index 0000000..3676a97 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-6.c @@ -0,0 +1,16 @@ +// Test the behavior of calloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ +/* { dg-set-target-env-var ASAN_OPTIONS "allocator_may_return_null=1" } */ + +#define ACTION "calloc" +#include "allocator_oom_test.inc" + +/* { dg-output "calloc:\nx: 0" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-7.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-7.c new file mode 100644 index 0000000..23094a1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-7.c @@ -0,0 +1,16 @@ +// Test the behavior of realloc-after-malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ + +#define ACTION "realloc-after-malloc" +#include "allocator_oom_test.inc" + +/* { dg-shouldfail "asan" } */ +/* { dg-output "realloc-after-malloc:\n==.*==AddressSanitizer's allocator is terminating the process" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test-8.c b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-8.c new file mode 100644 index 0000000..961c628 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test-8.c @@ -0,0 +1,16 @@ +// Test the behavior of realloc-after-malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +/* { dg-do run } */ +/* { dg-set-target-env-var ASAN_OPTIONS "allocator_may_return_null=1" } */ + +#define ACTION "realloc-after-malloc" +#include "allocator_oom_test.inc" + +/* { dg-output "realloc-after-malloc:\nx: 0" } */ diff --git a/gcc/testsuite/c-c++-common/asan/allocator_oom_test.inc b/gcc/testsuite/c-c++-common/asan/allocator_oom_test.inc new file mode 100644 index 0000000..2a74e65 --- /dev/null +++ b/gcc/testsuite/c-c++-common/asan/allocator_oom_test.inc @@ -0,0 +1,58 @@ +// Test the behavior of malloc/calloc/realloc when the allocation causes OOM +// in the secondary allocator. +// By default (allocator_may_return_null=0) the process should crash. +// With allocator_may_return_null=1 the allocator should return 0. +// Set the limit to 20.5T on 64 bits to account for ASan shadow memory, +// allocator buffers etc. so that the test allocation of ~1T will trigger OOM. +// Limit this test to Linux since we're relying on allocator internal +// limits (shadow memory size, allocation limits etc.) + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + struct rlimit new_lim; + new_lim.rlim_cur = 22024290304l; + new_lim.rlim_max = 4196971l; + setrlimit(RLIMIT_AS, &new_lim); + const char *action = ACTION; + fprintf(stderr, "%s:\n", action); + + // Allocate just a bit less than max allocation size enforced by ASan's + // allocator (currently 1T and 3G). + const size_t size = +#if __LP64__ + (1ULL << 40) - (1ULL << 30); +#else + (3ULL << 30) - (1ULL << 20); +#endif + + void *x = 0; + + if (!strcmp(action, "malloc")) { + x = malloc(size); + } else if (!strcmp(action, "calloc")) { + x = calloc(size / 4, 4); + } else if (!strcmp(action, "realloc")) { + x = realloc(0, size); + } else if (!strcmp(action, "realloc-after-malloc")) { + char *t = (char*)malloc(100); + *t = 42; + x = realloc(t, size); + assert(*t == 42); + free(t); + } else { + assert(0); + } + + // The NULL pointer is printed differently on different systems, while (long)0 + // is always the same. + fprintf(stderr, "x: %lx\n", (long)x); + free(x); + + return x != 0; +} -- 2.7.4 From 1c70d9e8e6aad835338fbd38d9083465a835b7b9 Mon Sep 17 00:00:00 2001 From: Dongkyun Son Date: Tue, 24 Oct 2017 10:22:21 +0900 Subject: [PATCH 12/16] packaging: add %arm to lsan_arch libasan.so.* are installed, but unpackaged in armv7hl. Change-Id: I713fdcc3b157f3578995fa26b9d8d4754f937bfa Signed-off-by: Dongkyun Son --- ChangeLog.Tizen | 4 ++++ packaging/gcc-aarch64.spec | 2 +- packaging/gcc-armv7hl.spec | 2 +- packaging/gcc-armv7l.spec | 2 +- packaging/linaro-gcc.spec | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ChangeLog.Tizen b/ChangeLog.Tizen index df9eeca..8748952 100644 --- a/ChangeLog.Tizen +++ b/ChangeLog.Tizen @@ -29,6 +29,10 @@ # log at the same time (actually you can't). However, if you update this # file after the commit hash is fixed, you are free to add the commit hash. ################################################################################ +2017-10-30 Dongkyun Son + + packaging: add %arm to lsan_arch + 2017-10-20 Slava Barinov [TTC-9] Enable recovery mode for ASan with leak detector diff --git a/packaging/gcc-aarch64.spec b/packaging/gcc-aarch64.spec index edce6d1..4cd7eee 100644 --- a/packaging/gcc-aarch64.spec +++ b/packaging/gcc-aarch64.spec @@ -28,7 +28,7 @@ %define asan_arch x86_64 %ix86 ppc ppc64 %sparc %arm aarch64 %define itm_arch x86_64 %ix86 %arm ppc ppc64 ppc64le s390 s390x %sparc aarch64 %define atomic_arch x86_64 %ix86 %arm aarch64 ppc ppc64 ppc64le s390 s390x %sparc m68k -%define lsan_arch x86_64 %ix86 armv7l aarch64 +%define lsan_arch x86_64 %ix86 %arm aarch64 %define ubsan_arch x86_64 %ix86 ppc ppc64 %arm aarch64 %define cilkrts_arch x86_64 %ix86 diff --git a/packaging/gcc-armv7hl.spec b/packaging/gcc-armv7hl.spec index f28b8d1..7ef98ad 100644 --- a/packaging/gcc-armv7hl.spec +++ b/packaging/gcc-armv7hl.spec @@ -28,7 +28,7 @@ %define asan_arch x86_64 %ix86 ppc ppc64 %sparc %arm aarch64 %define itm_arch x86_64 %ix86 %arm ppc ppc64 ppc64le s390 s390x %sparc aarch64 %define atomic_arch x86_64 %ix86 %arm aarch64 ppc ppc64 ppc64le s390 s390x %sparc m68k -%define lsan_arch x86_64 %ix86 armv7l aarch64 +%define lsan_arch x86_64 %ix86 %arm aarch64 %define ubsan_arch x86_64 %ix86 ppc ppc64 %arm aarch64 %define cilkrts_arch x86_64 %ix86 diff --git a/packaging/gcc-armv7l.spec b/packaging/gcc-armv7l.spec index 5bbfb4f..81846a5 100644 --- a/packaging/gcc-armv7l.spec +++ b/packaging/gcc-armv7l.spec @@ -28,7 +28,7 @@ %define asan_arch x86_64 %ix86 ppc ppc64 %sparc %arm aarch64 %define itm_arch x86_64 %ix86 %arm ppc ppc64 ppc64le s390 s390x %sparc aarch64 %define atomic_arch x86_64 %ix86 %arm aarch64 ppc ppc64 ppc64le s390 s390x %sparc m68k -%define lsan_arch x86_64 %ix86 armv7l aarch64 +%define lsan_arch x86_64 %ix86 %arm aarch64 %define ubsan_arch x86_64 %ix86 ppc ppc64 %arm aarch64 %define cilkrts_arch x86_64 %ix86 diff --git a/packaging/linaro-gcc.spec b/packaging/linaro-gcc.spec index 5f2a0ba..72c9b17 100644 --- a/packaging/linaro-gcc.spec +++ b/packaging/linaro-gcc.spec @@ -25,7 +25,7 @@ %define asan_arch x86_64 %ix86 ppc ppc64 %sparc %arm aarch64 %define itm_arch x86_64 %ix86 %arm ppc ppc64 ppc64le s390 s390x %sparc aarch64 %define atomic_arch x86_64 %ix86 %arm aarch64 ppc ppc64 ppc64le s390 s390x %sparc m68k -%define lsan_arch x86_64 %ix86 armv7l aarch64 +%define lsan_arch x86_64 %ix86 %arm aarch64 %define ubsan_arch x86_64 %ix86 ppc ppc64 %arm aarch64 %define cilkrts_arch x86_64 %ix86 -- 2.7.4 From 247fbfafcc633f5e1feac75a95a07a71c44764c7 Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Thu, 1 Jun 2017 16:21:11 +0300 Subject: [PATCH 13/16] Implement ISan: unsigned integer overflow checker. ISan in FE. Handle all s and u cases. Add unit and regression tests. Change-Id: I3f60f751598d904683264372541c2d3be0076768 --- gcc/builtins.c | 1 + gcc/c-family/c-common.c | 43 +++++++++-- gcc/c-family/c-ubsan.c | 87 +++++++++++++++++++++ gcc/c-family/c-ubsan.h | 4 + gcc/c/c-parser.c | 18 +++++ gcc/c/c-typeck.c | 74 ++++++++++++++++-- gcc/calls.c | 4 + gcc/cp/call.c | 1 + gcc/cp/class.c | 3 + gcc/cp/constexpr.c | 4 + gcc/cp/parser.c | 24 ++++++ gcc/cp/pt.c | 4 +- gcc/cp/typeck.c | 46 ++++++++++- gcc/doc/invoke.texi | 8 ++ gcc/flag-types.h | 3 +- gcc/fold-const.c | 13 +++- gcc/gimplify.c | 7 ++ gcc/internal-fn.c | 90 ++++++++++++++++++---- gcc/internal-fn.def | 3 + gcc/opts.c | 1 + gcc/testsuite/c-c++-common/isan/liveadder.c | 15 ++++ gcc/testsuite/c-c++-common/isan/miniperl.c | 13 ++++ gcc/testsuite/c-c++-common/isan/overflow-add.c | 51 ++++++++++++ gcc/testsuite/c-c++-common/isan/overflow-mul.c | 37 +++++++++ gcc/testsuite/c-c++-common/isan/overflow-sub.c | 50 ++++++++++++ .../c-c++-common/isan/static-initializer.c | 11 +++ gcc/testsuite/g++.dg/isan/cleanup.C | 11 +++ gcc/testsuite/g++.dg/isan/constexpr.C | 8 ++ gcc/testsuite/g++.dg/isan/isan.exp | 34 ++++++++ gcc/testsuite/gcc.dg/isan/false_positive.c | 19 +++++ gcc/testsuite/gcc.dg/isan/isan.exp | 36 +++++++++ gcc/tree-ssa-reassoc.c | 2 + gcc/tree.h | 3 +- gcc/ubsan.c | 12 ++- 34 files changed, 700 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/isan/liveadder.c create mode 100644 gcc/testsuite/c-c++-common/isan/miniperl.c create mode 100644 gcc/testsuite/c-c++-common/isan/overflow-add.c create mode 100644 gcc/testsuite/c-c++-common/isan/overflow-mul.c create mode 100644 gcc/testsuite/c-c++-common/isan/overflow-sub.c create mode 100644 gcc/testsuite/c-c++-common/isan/static-initializer.c create mode 100644 gcc/testsuite/g++.dg/isan/cleanup.C create mode 100644 gcc/testsuite/g++.dg/isan/constexpr.C create mode 100644 gcc/testsuite/g++.dg/isan/isan.exp create mode 100644 gcc/testsuite/gcc.dg/isan/false_positive.c create mode 100644 gcc/testsuite/gcc.dg/isan/isan.exp diff --git a/gcc/builtins.c b/gcc/builtins.c index bf66327..4ccd052 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -6771,6 +6771,7 @@ builtin_mathfn_code (const_tree t) const_call_expr_arg_iterator iter; if (TREE_CODE (t) != CALL_EXPR + || !CALL_EXPR_FN (t) || TREE_CODE (CALL_EXPR_FN (t)) != ADDR_EXPR) return END_BUILTINS; diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index c6eecaf..22420bb 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -4249,10 +4249,18 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, tree ptrop, tree intop, bool complain) { tree size_exp, ret; + HOST_WIDE_INT op1 = 0; /* The result is a pointer of the same type that is being added. */ tree result_type = TREE_TYPE (ptrop); + if (flag_sanitize & SANITIZE_UI_OVERFLOW) + { + /* First, try to avoid FPs if INTOP is negative constant. */ + if (tree_fits_shwi_p (intop)) + op1 = tree_to_shwi (intop); + } + if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE) { if (complain && warn_pointer_arith) @@ -4330,11 +4338,34 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, intop = wide_int_to_tree (TREE_TYPE (intop), intop); } - /* Create the sum or difference. */ - if (resultcode == MINUS_EXPR) - intop = fold_build1_loc (loc, NEGATE_EXPR, sizetype, intop); + if (flag_sanitize & SANITIZE_UI_OVERFLOW) + { + tree tmp = NULL_TREE; + /* First, try to avoid FPs if INTOP is negative constant. */ + if (op1 != 0) + { + if (op1 < 0) + { + resultcode = (resultcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR); + op1 = -op1; + } + tmp = build_int_cst (sizetype, op1); + intop = build_binary_op (loc, MULT_EXPR, tmp, + convert (TREE_TYPE (intop), size_exp), 1); + } + tmp = build_binary_op (loc, resultcode, + convert (sizetype, ptrop), + convert (long_integer_type_node, intop), 1); + ret = convert (result_type, tmp); + } + else + { + /* Create the sum or difference. */ + if (resultcode == MINUS_EXPR) + intop = fold_build1_loc (loc, NEGATE_EXPR, sizetype, intop); - ret = fold_build_pointer_plus_loc (loc, ptrop, intop); + ret = fold_build_pointer_plus_loc (loc, ptrop, intop); + } fold_undefer_and_ignore_overflow_warnings (); @@ -9732,7 +9763,9 @@ check_function_arguments_recurse (void (*callback) if (TREE_CODE (param) == CALL_EXPR) { - tree type = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (param))); + tree type + = CALL_EXPR_FN (param) ? TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (param))) + : TREE_TYPE (param); tree attrs; bool found_format_arg = false; diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c index 4022bdf..82ecc5b 100644 --- a/gcc/c-family/c-ubsan.c +++ b/gcc/c-family/c-ubsan.c @@ -456,3 +456,90 @@ ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor) if (op) CALL_EXPR_ARG (stmt, 0) = op; } + +/* Perform the unsigned and signed integer instrumentation for binary + operation CODE. LOC is the source location, RESULT_TYPE is computed type + for result of expression, OP0 and OP1 are corresponding operands. + UNS0_P and UNS1_P are bool flags indicating whether original OP0 and OP1 + were signed or unsigned. */ + +tree +isan_maybe_instrument_ui (location_t loc, enum tree_code code, + tree result_type, tree op0, tree op1, + int uns0_p, int uns1_p) +{ + tree op0type = TREE_TYPE (op0); + tree op1type = TREE_TYPE (op1); + + tree op0_uns_p = build_int_cst (integer_type_node, uns0_p); + tree op1_uns_p = build_int_cst (integer_type_node, uns1_p); + tree res_uns_p = build_int_cst (integer_type_node, + TYPE_UNSIGNED (result_type)); + + /* TODO: instrument even two constants. We don't do it right now to avoid + nasty errors in array bounds computations such as A[1 + 2 * sizeof (int)]. + */ + if ((TREE_CODE (op0) == INTEGER_CST) && (TREE_CODE (op1) == INTEGER_CST)) + return NULL_TREE; + + /* TODO: instrument for different precision modes. */ + if ((TYPE_PRECISION (op0type) != TYPE_PRECISION (result_type)) + || (TYPE_PRECISION (op1type) != TYPE_PRECISION (result_type))) + return NULL_TREE; + + /* If both operands are signed, don't instrument anything here. + Also punt on bit-fields. */ + if (!INTEGRAL_TYPE_P (op0type) || !INTEGRAL_TYPE_P (op1type) + || (!TYPE_OVERFLOW_WRAPS (op0type) && !TYPE_OVERFLOW_WRAPS (op1type)) + || GET_MODE_BITSIZE (TYPE_MODE (op0type)) != TYPE_PRECISION (op0type) + || GET_MODE_BITSIZE (TYPE_MODE (op1type)) != TYPE_PRECISION (op1type)) + return NULL_TREE; + + switch (code) + { + case MULT_EXPR: + case MINUS_EXPR: + case PLUS_EXPR: + /* Transform + i = u {+,-,*} 5; + into + i = ISAN_CHECK_{ADD,SUB,MUL} (u, 5); */ + return build_call_expr_internal_loc (loc, code == PLUS_EXPR + ? IFN_ISAN_CHECK_ADD + : code == MINUS_EXPR + ? IFN_ISAN_CHECK_SUB + : IFN_ISAN_CHECK_MUL, + result_type, 5, op0, op1, + op0_uns_p, op1_uns_p, + res_uns_p); + default: + break; + } + return NULL_TREE; +} + +/* Return TRUE iff FN is ISAN_CHECK_{ADD,SUB,MUL} internal function. */ + +bool +isan_internal_fn_p (tree fn) +{ + if (!fn || TREE_CODE (fn) != CALL_EXPR) + return false; + + enum internal_fn ifn = CALL_EXPR_IFN (fn); + return ifn == IFN_ISAN_CHECK_ADD || ifn == IFN_ISAN_CHECK_SUB + ||ifn == IFN_ISAN_CHECK_MUL; +} + +/* Change fourth (RES_UNS_P) parameter of ISAN_CHECK_{ADD,SUB,MUL} function + to UNS_P value. This is an extremely hacky way to avoid false psoitive + reports, because in many cases we simply cannot set RES_UNS_P value in + isan_maybe_instrument_ui correctly since we dont' see LHS and its type. */ + +void +isan_maybe_change_ifn_sign_arg (tree *call, int uns_p) +{ + tree *opp = &CALL_EXPR_ARG (*call, 4); + tree op_new = build_int_cst (integer_type_node, uns_p); + *opp = op_new; +} diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h index 30d4f97..a8202c0 100644 --- a/gcc/c-family/c-ubsan.h +++ b/gcc/c-family/c-ubsan.h @@ -23,6 +23,8 @@ along with GCC; see the file COPYING3. If not see extern tree ubsan_instrument_division (location_t, tree, tree); extern tree ubsan_instrument_shift (location_t, enum tree_code, tree, tree); +extern tree isan_maybe_instrument_ui (location_t, enum tree_code, + tree, tree, tree, int, int); extern tree ubsan_instrument_vla (location_t, tree); extern tree ubsan_instrument_return (location_t); extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool); @@ -33,5 +35,7 @@ extern void ubsan_maybe_instrument_member_call (tree, bool); /* Declare this here as well as in ubsan.h. */ extern bool do_ubsan_in_current_function (void); +extern bool isan_internal_fn_p (tree fn); +extern void isan_maybe_change_ifn_sign_arg (tree *, int); #endif /* GCC_C_UBSAN_H */ diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index c9eb8dd..35f383e 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see #include "varasm.h" #include "trans-mem.h" #include "c-family/c-pragma.h" +#include "c-family/c-ubsan.h" #include "c-lang.h" #include "c-family/c-objc.h" #include "plugin.h" @@ -262,6 +263,8 @@ struct GTY(()) c_parser { static GTY (()) c_parser *the_parser; +bool processing_static_variable; + /* Read in and lex a single token, storing it in *TOKEN. */ static void @@ -1927,6 +1930,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, its initializer is parsed. */ d = start_decl (declarator, specs, true, chainon (postfix_attrs, all_prefix_attrs)); + + if (d && TREE_STATIC (d)) + processing_static_variable = true; + if (!d) d = error_mark_node; if (omp_declare_simd_clauses.exists () @@ -1936,7 +1943,12 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, start_init (d, asm_name, global_bindings_p ()); init_loc = c_parser_peek_token (parser)->location; init = c_parser_initializer (parser); + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (init.value)) + isan_maybe_change_ifn_sign_arg (&init.value, + TYPE_UNSIGNED (TREE_TYPE (d))); finish_init (); + processing_static_variable = false; } if (oacc_routine_clauses) c_finish_oacc_routine (parser, d, oacc_routine_clauses, @@ -5212,6 +5224,12 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, location_t xloc = c_parser_peek_token (parser)->location; struct c_expr expr = c_parser_expression_conv (parser); mark_exp_read (expr.value); + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (expr.value)) + { + int uns_p = TYPE_UNSIGNED (TREE_TYPE (DECL_RESULT (current_function_decl))); + isan_maybe_change_ifn_sign_arg (&expr.value, uns_p); + } stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc), expr.value, expr.original_type); goto expect_semicolon; diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 2bea816..5793a4a 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -72,6 +72,8 @@ int in_typeof; if expr.original_code == SIZEOF_EXPR. */ tree c_last_sizeof_arg; +extern bool processing_static_variable; + /* Nonzero if we might need to print a "missing braces around initializer" message within this initializer. */ static int found_missing_braces; @@ -3020,6 +3022,21 @@ build_function_call_vec (location_t loc, vec arg_loc, if (nargs < 0) return error_mark_node; + for (int i = 0; i < nargs; ++i) + { + tree tmp = (*params)[i]; + if (TREE_CODE (tmp) == NOP_EXPR) + { + int real_type_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (tmp)); + tree arg = TREE_OPERAND (tmp, 0); + if (isan_internal_fn_p (arg)) + { + tree *arg_p = &TREE_OPERAND ((*params)[i], 0); + isan_maybe_change_ifn_sign_arg (arg_p, real_type_unsigned_p); + } + } + } + /* Check that the function is called through a compatible prototype. If it is not, warn. */ if (CONVERT_EXPR_P (function) @@ -5570,6 +5587,13 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, newrhs = rhs; + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (rhs)) + { + tree lhs_type = lhs_origtype ? lhs_origtype : TREE_TYPE (lhs); + isan_maybe_change_ifn_sign_arg (&newrhs, TYPE_UNSIGNED (lhs_type)); + } + if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR) { tree inner = build_modify_expr (location, C_MAYBE_CONST_EXPR_EXPR (lhs), @@ -5607,6 +5631,12 @@ build_modify_expr (location_t location, tree lhs, tree lhs_origtype, } newrhs = build_binary_op (location, modifycode, lhs, newrhs, 1); + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (newrhs)) + { + tree lhs_type = lhs_origtype ? lhs_origtype : TREE_TYPE (lhs); + isan_maybe_change_ifn_sign_arg (&newrhs, TYPE_UNSIGNED (lhs_type)); + } /* The original type of the right hand side is no longer meaningful. */ @@ -10577,6 +10607,10 @@ build_binary_op (location_t location, enum tree_code code, /* Remember whether we're doing << or >>. */ bool doing_shift = false; + bool doing_plus = false; + bool doing_minus = false; + bool doing_mul = false; + /* Tree holding instrumentation expression. */ tree instrument_expr = NULL; @@ -10757,7 +10791,10 @@ build_binary_op (location_t location, enum tree_code code, goto return_build_binary_op; } else - common = 1; + { + doing_plus = true; + common = 1; + } break; case MINUS_EXPR: @@ -10776,10 +10813,14 @@ build_binary_op (location_t location, enum tree_code code, goto return_build_binary_op; } else - common = 1; + { + doing_minus = true; + common = 1; + } break; case MULT_EXPR: + doing_mul = true; common = 1; break; @@ -11607,6 +11648,20 @@ build_binary_op (location_t location, enum tree_code code, instrument_expr = ubsan_instrument_shift (location, code, op0, op1); } + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && (doing_plus || doing_minus || doing_mul) + && !processing_static_variable) + { + op0 = c_save_expr (op0); + op1 = c_save_expr (op1); + op0 = c_fully_fold (op0, false, NULL); + op1 = c_fully_fold (op1, false, NULL); + instrument_expr = isan_maybe_instrument_ui (location, code, + result_type, op0, op1, + TYPE_UNSIGNED (orig_type0), + TYPE_UNSIGNED (orig_type1)); + } + /* Treat expressions in initializers specially as they can't trap. */ if (int_const_or_overflow) ret = (require_constant_value @@ -11632,9 +11687,18 @@ build_binary_op (location_t location, enum tree_code code, protected_set_expr_location (ret, location); if (instrument_expr != NULL) - ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), - instrument_expr, ret); - + { + if (flag_sanitize & SANITIZE_UI_OVERFLOW) + { + /* Inherit side effects. TODO: what another attributes should be + inherited? */ + TREE_SIDE_EFFECTS (instrument_expr) = TREE_SIDE_EFFECTS (ret); + ret = instrument_expr; + } + else + ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), + instrument_expr, ret); + } return ret; } diff --git a/gcc/calls.c b/gcc/calls.c index 8de22f3..a39fc86 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -795,6 +795,10 @@ call_expr_flags (const_tree t) int flags; tree decl = get_callee_fndecl (t); + /* We may have UBSan internal functions here. */ + if (!CALL_EXPR_FN (t)) + return ECF_CONST | ECF_LEAF | ECF_NOTHROW; + if (decl) flags = flags_from_decl_or_type (decl); else if (CALL_EXPR_FN (t) == NULL_TREE) diff --git a/gcc/cp/call.c b/gcc/cp/call.c index a7d35b9..cbc3ec6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "convert.h" #include "langhooks.h" #include "c-family/c-objc.h" +#include "c-family/c-ubsan.h" #include "internal-fn.h" /* The various kinds of conversion. */ diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 35deb1e..ceff3ef 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" #include "gimplify.h" #include "intl.h" +#include "c-family/c-ubsan.h" /* The number of nested classes being processed. If we are not in the scope of any class, this is zero. */ @@ -7497,6 +7498,8 @@ fixed_type_or_null (tree instance, int *nonnull, int *cdtorp) return RECUR (TREE_OPERAND (instance, 0)); case CALL_EXPR: + if (isan_internal_fn_p (instance)) + return RECUR (TREE_OPERAND (instance, 0)); /* This is a call to a constructor, hence it's never zero. */ if (TREE_HAS_CONSTRUCTOR (instance)) { diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index f9c4ead..cff531e 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -4730,6 +4730,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, case IFN_UBSAN_BOUNDS: case IFN_UBSAN_VPTR: return true; + case IFN_ISAN_CHECK_ADD: + case IFN_ISAN_CHECK_SUB: + case IFN_ISAN_CHECK_MUL: + return false; default: break; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 187fe0e..bb2d371 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "decl.h" #include "c-family/c-objc.h" +#include "c-family/c-ubsan.h" #include "plugin.h" #include "tree-pretty-print.h" #include "parser.h" @@ -9083,6 +9084,14 @@ cp_parser_assignment_expression (cp_parser* parser, cp_id_kind * pidk, cp_expr rhs = cp_parser_initializer_clause (parser, &non_constant_p); + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (rhs)) + { + int uns_p = TYPE_UNSIGNED (TREE_TYPE (expr)); + tree rhs_value = rhs.get_value(); + isan_maybe_change_ifn_sign_arg (&rhs_value, uns_p); + } + if (BRACE_ENCLOSED_INITIALIZER_P (rhs)) maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); @@ -11834,6 +11843,15 @@ cp_parser_jump_statement (cp_parser* parser) /* If the next token is a `;', then there is no expression. */ expr = NULL_TREE; + + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (expr)) + { + int uns_p = TYPE_UNSIGNED (TREE_TYPE + (DECL_RESULT (current_function_decl))); + isan_maybe_change_ifn_sign_arg (&expr, uns_p); + } + /* Build the return-statement. */ statement = finish_return_stmt (expr); /* Look for the final `;'. */ @@ -18677,6 +18695,12 @@ cp_parser_init_declarator (cp_parser* parser, finish_lambda_scope (); if (initializer == error_mark_node) cp_parser_skip_to_end_of_statement (parser); + else if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (initializer)) + { + int uns_p = TYPE_UNSIGNED (TREE_TYPE (decl)); + isan_maybe_change_ifn_sign_arg (&initializer, uns_p); + } } } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index db403c8..a98a5dc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -22860,6 +22860,8 @@ value_dependent_expression_p (tree expression) case CALL_EXPR: { + if (!CALL_EXPR_FN (expression)) + return false; tree fn = get_callee_fndecl (expression); int i, nargs; if (!fn && value_dependent_expression_p (CALL_EXPR_FN (expression))) @@ -23224,7 +23226,7 @@ instantiation_dependent_r (tree *tp, int *walk_subtrees, case CALL_EXPR: /* Treat calls to function concepts as dependent. */ - if (function_concept_check_p (*tp)) + if (CALL_EXPR_FN (*tp) && function_concept_check_p (*tp)) return *tp; break; diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 029d0ab..b5a9dd0 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -4060,6 +4060,9 @@ cp_build_binary_op (location_t location, tree result, result_ovl; tree orig_type = NULL; + tree orig_type0 = TREE_TYPE (orig_op0); + tree orig_type1 = TREE_TYPE (orig_op1); + /* Nonzero if this is an operation like MIN or MAX which can safely be computed in short if both args are promoted shorts. Also implies COMMON. @@ -4089,6 +4092,10 @@ cp_build_binary_op (location_t location, /* Remember whether we're doing << or >>. */ bool doing_shift = false; + bool doing_plus = false; + bool doing_minus = false; + bool doing_mul = false; + /* Tree holding instrumentation expression. */ tree instrument_expr = NULL; @@ -4231,6 +4238,7 @@ cp_build_binary_op (location_t location, else if (!(code0 == POINTER_TYPE && code1 == INTEGER_TYPE)) { common = 1; + doing_minus = 1; break; } /* The pointer - int case is just like pointer + int; fall @@ -4254,10 +4262,12 @@ cp_build_binary_op (location_t location, complain); } common = 1; + doing_plus = 1; break; case MULT_EXPR: common = 1; + doing_mul = 1; break; case TRUNC_DIV_EXPR: @@ -5153,13 +5163,37 @@ cp_build_binary_op (location_t location, instrument_expr = ubsan_instrument_shift (location, code, op0, op1); } + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && (doing_plus || doing_minus || doing_mul) + && !processing_template_decl) + { + op0 = cp_save_expr (op0); + op1 = cp_save_expr (op1); + op0 = fold_non_dependent_expr (op0); + op1 = fold_non_dependent_expr (op1); + instrument_expr = isan_maybe_instrument_ui (location, code, + result_type, op0, op1, + TYPE_UNSIGNED (orig_type0), + TYPE_UNSIGNED (orig_type1)); + } + result = build2_loc (location, resultcode, build_type, op0, op1); if (final_type != 0) result = cp_convert (final_type, result, complain); if (instrument_expr != NULL) - result = build2 (COMPOUND_EXPR, TREE_TYPE (result), - instrument_expr, result); + { + if (flag_sanitize & SANITIZE_UI_OVERFLOW) + { + /* Inherit side effects. TODO: what another attributes should be + inherited? */ + TREE_SIDE_EFFECTS (instrument_expr) = TREE_SIDE_EFFECTS (result); + result = instrument_expr; + } + else + result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result), + instrument_expr, result); + } if (!processing_template_decl) { @@ -7672,6 +7706,14 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs, newrhs = cp_build_binary_op (input_location, modifycode, lhs, rhs, complain); + + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && isan_internal_fn_p (newrhs)) + { + int uns_p = TYPE_UNSIGNED (TREE_TYPE (lhs)); + isan_maybe_change_ifn_sign_arg (&newrhs, uns_p); + } + if (newrhs == error_mark_node) { if (complain & tf_error) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index f2f34e8..338b326 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9856,6 +9856,14 @@ signed char a = SCHAR_MAX; a++; @end smallexample +@item -fsanitize=unsigned-integer-overflow +@opindex fsanitize=unsigned-integer-overflow +This option enables unsigned and mixed (signed/unsigned) integer overflow +checking. We check that the result of @code{+}, @code{*}, and binary @code{-} +does not overflow in the unsigned or mixed arithmetics. These checks can +trigger false positive warnings on code that intentionally relies on overflows, +e.g. when computing hash codes. + @item -fsanitize=bounds @opindex fsanitize=bounds This option enables instrumentation of array bounds. Various out of bounds diff --git a/gcc/flag-types.h b/gcc/flag-types.h index 8201676..18cf0a3 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -253,6 +253,7 @@ enum sanitize_code { SANITIZE_OBJECT_SIZE = 1UL << 20, SANITIZE_VPTR = 1UL << 21, SANITIZE_BOUNDS_STRICT = 1UL << 22, + SANITIZE_UI_OVERFLOW = 1 << 23, SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM @@ -261,7 +262,7 @@ enum sanitize_code { | SANITIZE_RETURNS_NONNULL_ATTRIBUTE | SANITIZE_OBJECT_SIZE | SANITIZE_VPTR, SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST - | SANITIZE_BOUNDS_STRICT + | SANITIZE_BOUNDS_STRICT | SANITIZE_UI_OVERFLOW }; /* flag_vtable_verify initialization levels. */ diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 46f1ac1..17ff640 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -386,7 +386,8 @@ negate_expr_p (tree t) switch (TREE_CODE (t)) { case INTEGER_CST: - if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type)) + if (INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type) + && !TYPE_OVERFLOW_SANITIZED (type)) return true; /* Check that -CST will not overflow type. */ @@ -549,8 +550,8 @@ fold_negate_expr (location_t loc, tree t) if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t) || (ANY_INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_TRAPS (type) - && TYPE_OVERFLOW_WRAPS (type)) - || (flag_sanitize & SANITIZE_SI_OVERFLOW) == 0) + && !TYPE_OVERFLOW_SANITIZED (type)) + || (flag_sanitize & (SANITIZE_SI_OVERFLOW | SANITIZE_UI_OVERFLOW)) == 0) return tem; break; @@ -9966,7 +9967,11 @@ fold_binary_loc (location_t loc, return tem; } - goto associate; + /* Associate if we don't sanitize unsigned integer overflows. */ + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) == 0) + goto associate; + + return NULL_TREE; case MULT_EXPR: if (! FLOAT_TYPE_P (type)) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 22e053a..ee6d2b5 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2371,6 +2371,13 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value) enum internal_fn ifn = CALL_EXPR_IFN (*expr_p); auto_vec vargs (nargs); + /* Ugh, sometimes FE can optimize conditional thus it doesn't + depend on ISAN_*_CHECK return value. Don't fold the check in this + case, but we'll probably want introduce temporary here. */ + if (ifn == IFN_ISAN_CHECK_ADD || ifn == IFN_ISAN_CHECK_SUB + || ifn == IFN_ISAN_CHECK_MUL) + return GS_ALL_DONE; + for (i = 0; i < nargs; i++) { gimplify_arg (&CALL_EXPR_ARG (*expr_p, i), pre_p, diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index f6805d0..1523a91 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -463,9 +463,8 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs, int prec = GET_MODE_PRECISION (mode); rtx sgn = immed_wide_int_const (wi::min_value (prec, SIGNED), mode); bool do_xor = false; - - if (is_ubsan) - gcc_assert (!unsr_p && !uns0_p && !uns1_p); + tree orig_arg0 = arg0; + tree orig_arg1 = arg1; if (lhs) { @@ -853,8 +852,8 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs, { /* Expand the ubsan builtin call. */ push_temp_slots (); - fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (arg0), - arg0, arg1); + fn = ubsan_build_overflow_builtin (code, loc, TREE_TYPE (lhs), + orig_arg0, orig_arg1); expand_normal (fn); pop_temp_slots (); do_pending_stack_adjust (); @@ -868,7 +867,12 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs, if (lhs) { if (is_ubsan) - expand_ubsan_result_store (target, res); + { + if (do_xor) + res = expand_binop (mode, add_optab, res, sgn, NULL_RTX, false, + OPTAB_LIB_WIDEN); + expand_ubsan_result_store (target, res); + } else { if (do_xor) @@ -981,6 +985,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, rtx target = NULL_RTX; signop sign; enum insn_code icode; + tree orig_arg0 = arg0; + tree orig_arg1 = arg1; done_label = gen_label_rtx (); do_error = gen_label_rtx (); @@ -998,9 +1004,6 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, write_complex_part (target, const0_rtx, true); } - if (is_ubsan) - gcc_assert (!unsr_p && !uns0_p && !uns1_p); - /* We assume both operands and result have the same precision here (GET_MODE_BITSIZE (mode)), S stands for signed type with that precision, U for unsigned type with that precision, @@ -1081,7 +1084,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, NULL, do_main_label, PROB_VERY_LIKELY); do_compare_rtx_and_jump (op1, const0_rtx, EQ, true, mode, NULL_RTX, NULL, do_main_label, PROB_VERY_LIKELY); - write_complex_part (target, const1_rtx, true); + if (!is_ubsan) + write_complex_part (target, const1_rtx, true); emit_label (do_main_label); goto do_main; default: @@ -1212,7 +1216,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, is, thus we can keep do_main code oring in overflow as is. */ do_compare_rtx_and_jump (tem, const0_rtx, EQ, true, mode, NULL_RTX, NULL, do_main_label, PROB_VERY_LIKELY); - write_complex_part (target, const1_rtx, true); + if (!is_ubsan) + write_complex_part (target, const1_rtx, true); emit_label (do_main_label); goto do_main; default: @@ -1609,8 +1614,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, { /* Expand the ubsan builtin call. */ push_temp_slots (); - fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (arg0), - arg0, arg1); + fn = ubsan_build_overflow_builtin (MULT_EXPR, loc, TREE_TYPE (lhs), + orig_arg0, orig_arg1); expand_normal (fn); pop_temp_slots (); do_pending_stack_adjust (); @@ -1627,7 +1632,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, rtx_code_label *all_done_label = gen_label_rtx (); do_compare_rtx_and_jump (res, const0_rtx, GE, false, mode, NULL_RTX, NULL, all_done_label, PROB_VERY_LIKELY); - write_complex_part (target, const1_rtx, true); + if (!is_ubsan) + write_complex_part (target, const1_rtx, true); emit_label (all_done_label); } @@ -1638,7 +1644,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, rtx_code_label *set_noovf = gen_label_rtx (); do_compare_rtx_and_jump (op1, const0_rtx, GE, false, mode, NULL_RTX, NULL, all_done_label, PROB_VERY_LIKELY); - write_complex_part (target, const1_rtx, true); + if (!is_ubsan) + write_complex_part (target, const1_rtx, true); do_compare_rtx_and_jump (op0, const0_rtx, EQ, true, mode, NULL_RTX, NULL, set_noovf, PROB_VERY_LIKELY); do_compare_rtx_and_jump (op0, constm1_rtx, NE, true, mode, NULL_RTX, @@ -1646,7 +1653,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, do_compare_rtx_and_jump (op1, res, NE, true, mode, NULL_RTX, NULL, all_done_label, PROB_VERY_UNLIKELY); emit_label (set_noovf); - write_complex_part (target, const0_rtx, true); + if (!is_ubsan) + write_complex_part (target, const0_rtx, true); emit_label (all_done_label); } @@ -1659,6 +1667,56 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1, } } +/* Expand ISAN_CHECK_ADD call STMT. */ + +static void +expand_ISAN_CHECK_ADD (internal_fn, gcall *stmt) +{ + location_t loc = gimple_location (stmt); + tree lhs = gimple_call_lhs (stmt); + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + int uns0_p = tree_to_shwi (gimple_call_arg (stmt, 2)); + int uns1_p = tree_to_shwi (gimple_call_arg (stmt, 3)); + int unsr_p = tree_to_shwi (gimple_call_arg (stmt, 4)); + expand_addsub_overflow (loc, PLUS_EXPR, lhs, arg0, arg1, + unsr_p, uns0_p, uns1_p, true); +} + +/* Expand ISAN_CHECK_SUB call STMT. */ + +static void +expand_ISAN_CHECK_SUB (internal_fn, gcall *stmt) +{ + location_t loc = gimple_location (stmt); + tree lhs = gimple_call_lhs (stmt); + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + int uns0_p = tree_to_shwi (gimple_call_arg (stmt, 2)); + int uns1_p = tree_to_shwi (gimple_call_arg (stmt, 3)); + int unsr_p = tree_to_shwi (gimple_call_arg (stmt, 4)); + if (integer_zerop (arg0)) + expand_neg_overflow (loc, lhs, arg1, true); + else + expand_addsub_overflow (loc, MINUS_EXPR, lhs, arg0, arg1, + unsr_p, uns0_p, uns1_p, true); +} + +/* Expand ISAN_CHECK_MUL call STMT. */ + +static void +expand_ISAN_CHECK_MUL (internal_fn, gcall *stmt) +{ + location_t loc = gimple_location (stmt); + tree lhs = gimple_call_lhs (stmt); + tree arg0 = gimple_call_arg (stmt, 0); + tree arg1 = gimple_call_arg (stmt, 1); + int uns0_p = tree_to_shwi (gimple_call_arg (stmt, 2)); + int uns1_p = tree_to_shwi (gimple_call_arg (stmt, 3)); + int unsr_p = tree_to_shwi (gimple_call_arg (stmt, 4)); + expand_mul_overflow (loc, lhs, arg0, arg1, uns0_p, uns1_p, unsr_p, true); +} + /* Expand UBSAN_CHECK_ADD call STMT. */ static void diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index a62f3e8..761576d7 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -154,6 +154,9 @@ DEF_INTERNAL_FN (UBSAN_VPTR, ECF_LEAF | ECF_NOTHROW, ".RR..") DEF_INTERNAL_FN (UBSAN_CHECK_ADD, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (UBSAN_CHECK_SUB, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (UBSAN_CHECK_MUL, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (ISAN_CHECK_ADD, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (ISAN_CHECK_SUB, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (ISAN_CHECK_MUL, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL) DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) diff --git a/gcc/opts.c b/gcc/opts.c index 0f9431a..99542cb 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1454,6 +1454,7 @@ const struct sanitizer_opts_s sanitizer_opts[] = SANITIZER_OPT (return, SANITIZE_RETURN), SANITIZER_OPT (null, SANITIZE_NULL), SANITIZER_OPT (signed-integer-overflow, SANITIZE_SI_OVERFLOW), + SANITIZER_OPT (unsigned-integer-overflow, SANITIZE_UI_OVERFLOW), SANITIZER_OPT (bool, SANITIZE_BOOL), SANITIZER_OPT (enum, SANITIZE_ENUM), SANITIZER_OPT (float-divide-by-zero, SANITIZE_FLOAT_DIVIDE), diff --git a/gcc/testsuite/c-c++-common/isan/liveadder.c b/gcc/testsuite/c-c++-common/isan/liveadder.c new file mode 100644 index 0000000..d76bc22 --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/liveadder.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow" } */ + +__extension__ typedef signed long long gint64; +__extension__ typedef unsigned long long guint64; +typedef signed int gint32; +typedef unsigned int guint32; +typedef int gint; + +static void add_uint32 (guint32 *out, guint32 *in, gint bytes) +{ + gint i; + for (i = 0; i < bytes / sizeof (guint32); i++) + out[i] = ((((guint64)out[i] + (guint64)in[i]) > 1) ? 111111111 : (((guint64)out[i] + (guint64)in[i]) < 0) ? 0 : 1111111); +} diff --git a/gcc/testsuite/c-c++-common/isan/miniperl.c b/gcc/testsuite/c-c++-common/isan/miniperl.c new file mode 100644 index 0000000..1887373 --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/miniperl.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow -fdump-tree-gimple" } */ + +extern int *PL_tmps_stack; + +void foo (int items, int tmpsbase) { + int i = items; + while (i-- > 0) + PL_tmps_stack[--tmpsbase] |= 3; + return; +} + +/* { dg-final { scan-tree-dump-times "ISAN_CHECK_ADD" 1 "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/isan/overflow-add.c b/gcc/testsuite/c-c++-common/isan/overflow-add.c new file mode 100644 index 0000000..0003842 --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/overflow-add.c @@ -0,0 +1,51 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow" } */ + +#include +#include + +#define CHECK_ADD(type1, type2, type3, val1, val2) \ + do { \ + volatile type1 a = val1; \ + volatile type2 b = val2; \ + volatile type3 c = a + b; \ + asm volatile ("" : : "r" (c) : "memory"); \ + } while (0) + +int main () { + + CHECK_ADD(uint32_t, uint32_t, uint32_t, UINT32_MAX, 1); + CHECK_ADD(uint32_t, uint32_t, int32_t, UINT32_MAX, 1); + CHECK_ADD(uint32_t, int32_t, uint32_t, UINT32_MAX, 1); + CHECK_ADD(uint32_t, int32_t, int32_t, UINT32_MAX, 1); + CHECK_ADD(uint32_t, uint32_t, uint32_t, INT32_MAX, 1); + CHECK_ADD(uint32_t, int32_t, int32_t, INT32_MAX, -1); + + CHECK_ADD(uint64_t, uint64_t, uint64_t, UINT64_MAX, 1); + CHECK_ADD(uint64_t, uint64_t, int64_t, UINT64_MAX, 1); + CHECK_ADD(uint64_t, int64_t, uint64_t, UINT64_MAX, 1); + CHECK_ADD(uint64_t, int64_t, int64_t, UINT64_MAX, 1); + CHECK_ADD(uint64_t, uint64_t, uint64_t, INT64_MAX, 1); + CHECK_ADD(uint64_t, int64_t, uint64_t, INT64_MAX, -1); + + CHECK_ADD(int8_t *, unsigned, int8_t *, (int8_t *) UINT64_MAX, 1); + CHECK_ADD(int32_t *, unsigned, int32_t *, (int32_t *) UINT64_MAX, 1); + CHECK_ADD(int64_t *, unsigned, int64_t *, (int64_t *) UINT64_MAX, 1); + CHECK_ADD(int8_t *, unsigned, int8_t *, (int8_t *) SIZE_MAX, 1); + CHECK_ADD(int8_t *, signed, int8_t *, (int8_t *) SIZE_MAX, -1); + + return 0; +} + + +/* { dg-output "unsigned integer overflow: 4294967295 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 4294967295 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 4294967295 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 4294967295 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 18446744073709551615 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 18446744073709551615 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 18446744073709551615 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 18446744073709551615 \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: \[0-9\]+ \\+ 1 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: \[0-9\]+ \\+ 4 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: \[0-9\]+ \\+ 8 cannot be represented in type '.*'" } */ diff --git a/gcc/testsuite/c-c++-common/isan/overflow-mul.c b/gcc/testsuite/c-c++-common/isan/overflow-mul.c new file mode 100644 index 0000000..7e29eb1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/overflow-mul.c @@ -0,0 +1,37 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow" } */ + +#include + +#define CHECK_MUL(sign1, sign2, sign3, type1, type2, type3, val1, val2) \ + do { \ + volatile sign1 type1 a = val1; \ + volatile sign2 type2 b = val2; \ + volatile sign3 type3 c = a * b; \ + } while (0) + +int main () { + + CHECK_MUL(unsigned, unsigned, unsigned, int, int, int, 2, UINT_MAX); + CHECK_MUL(unsigned, unsigned, signed, int, int, int, 2, UINT_MAX); + CHECK_MUL(signed, unsigned, unsigned, int, int, int, 2, UINT_MAX); + CHECK_MUL(signed, unsigned, signed, int, int, int, 2, UINT_MAX); + CHECK_MUL(unsigned, unsigned, unsigned, int, int, int, 2, INT_MAX); + CHECK_MUL(signed, signed, signed, int, int, int, -2, INT_MAX); + + CHECK_MUL(unsigned, unsigned, unsigned, long, long, long, 2, ULONG_MAX); + CHECK_MUL(unsigned, unsigned, signed, long, long, long, 2, ULONG_MAX); + CHECK_MUL(signed, unsigned, unsigned, long, long, long, 2, ULONG_MAX); + CHECK_MUL(signed, unsigned, signed, long, long, long, 2, ULONG_MAX); + CHECK_MUL(unsigned, unsigned, unsigned, long, long, long, 2, LONG_MAX); + CHECK_MUL(signed, signed, signed, long, long, long, -2, LONG_MAX); + + return 0; +} + +/* { dg-output "unsigned integer overflow: 2 \\* 4294967295 cannot be represented in type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 2 \\* 4294967295 cannot be represented in type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 2 \\* 4294967295 cannot be represented in type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 2 \\* 18446744073709551615 cannot be represented in type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 2 \\* 18446744073709551615 cannot be represented in type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 2 \\* 18446744073709551615 cannot be represented in type 'long unsigned int'" } */ diff --git a/gcc/testsuite/c-c++-common/isan/overflow-sub.c b/gcc/testsuite/c-c++-common/isan/overflow-sub.c new file mode 100644 index 0000000..fe03df2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/overflow-sub.c @@ -0,0 +1,50 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow" } */ + +#include +#include + +#define CHECK_SUB(type1, type2, type3, val1, val2) \ + do { \ + volatile type1 a = val1; \ + volatile type2 b = val2; \ + volatile type3 c = a - b; \ + asm volatile ("" : : "r" (c) : "memory"); \ + } while (0) + +int main () { + + CHECK_SUB(uint32_t, uint32_t, uint32_t, 1, UINT32_MAX); + CHECK_SUB(uint32_t, uint32_t, int32_t, 1, UINT32_MAX); + CHECK_SUB(int32_t, uint32_t, uint32_t, 1, UINT32_MAX); + CHECK_SUB(int32_t, uint32_t, int32_t, 1, UINT32_MAX); + CHECK_SUB(uint32_t, uint32_t, uint32_t, 1, 1); + CHECK_SUB(uint32_t, int32_t, uint32_t, 1, -1); + + CHECK_SUB(uint64_t, uint64_t, uint64_t, 1, UINT64_MAX); + CHECK_SUB(uint64_t, uint64_t, int64_t, 1, UINT64_MAX); + CHECK_SUB(int64_t, uint64_t, uint64_t, 1, UINT64_MAX); + CHECK_SUB(int64_t, uint64_t, int64_t, 1, UINT64_MAX); + CHECK_SUB(uint64_t, uint64_t, uint64_t, 1, 1); + CHECK_SUB(uint64_t, int64_t, uint64_t, 1, -1); + + CHECK_SUB(int8_t *, unsigned, int8_t *, (int8_t *) 1, 2); + CHECK_SUB(int32_t *, unsigned, int32_t *, (int32_t *) 1, 2); + CHECK_SUB(int64_t *, unsigned, int64_t *, (int64_t *) 1, 2); + CHECK_SUB(int8_t *, unsigned, int8_t *, (int8_t *) 1, 1); + CHECK_SUB(int8_t *, signed, int8_t *, (int8_t *) 1, -1); + + return 0; +} + +/* { dg-output "unsigned integer overflow: 1 \\- 4294967295 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 4294967295 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 4294967295 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 4294967295 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 18446744073709551615 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 18446744073709551615 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 18446744073709551615 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 18446744073709551615 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 2 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 8 cannot be represented in type '.*'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*unsigned integer overflow: 1 \\- 16 cannot be represented in type '.*'" } */ diff --git a/gcc/testsuite/c-c++-common/isan/static-initializer.c b/gcc/testsuite/c-c++-common/isan/static-initializer.c new file mode 100644 index 0000000..6bca344c --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/static-initializer.c @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow -fdump-tree-gimple" } */ + +char a; + +void foo () { + static char *b = &a + 14; + char *c = &a + 14; +} + +/* { dg-final { scan-tree-dump "ISAN_CHECK_ADD" "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/isan/cleanup.C b/gcc/testsuite/g++.dg/isan/cleanup.C new file mode 100644 index 0000000..38598f8 --- /dev/null +++ b/gcc/testsuite/g++.dg/isan/cleanup.C @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow" } */ + +#include + +extern void bar (); + +void foo (std::string &s) { + for (int i = 0; i < 20 - s.substr(1, 6).length(); ++i) + bar (); +} diff --git a/gcc/testsuite/g++.dg/isan/constexpr.C b/gcc/testsuite/g++.dg/isan/constexpr.C new file mode 100644 index 0000000..4896396 --- /dev/null +++ b/gcc/testsuite/g++.dg/isan/constexpr.C @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow -std=gnu++11" } */ + +#include + +constexpr int foo (int i) { + return std::__lg (i); +} diff --git a/gcc/testsuite/g++.dg/isan/isan.exp b/gcc/testsuite/g++.dg/isan/isan.exp new file mode 100644 index 0000000..d4af573 --- /dev/null +++ b/gcc/testsuite/g++.dg/isan/isan.exp @@ -0,0 +1,34 @@ +# Copyright (C) 2013-2015 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Load support procs. +load_lib g++-dg.exp +load_lib ubsan-dg.exp + +# Initialize `dg'. +dg-init +ubsan_init + +# Main loop. +if [check_effective_target_fsanitize_undefined] { + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C $srcdir/c-c++-common/isan/*.c]] "" "" +} + +# All done. +ubsan_finish +dg-finish diff --git a/gcc/testsuite/gcc.dg/isan/false_positive.c b/gcc/testsuite/gcc.dg/isan/false_positive.c new file mode 100644 index 0000000..a2b245e --- /dev/null +++ b/gcc/testsuite/gcc.dg/isan/false_positive.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow" } */ +/* { dg-set-target-env-var UBSAN_OPTIONS "halt_on_error=1" } */ + +int foo (int c) { +}; + +int bar (unsigned a, unsigned b) { + return a - b; +} + +int main() { + unsigned a = 1; + unsigned b = 2; + + int c = a - b; + foo (a - b); + c = bar (a, b); +} diff --git a/gcc/testsuite/gcc.dg/isan/isan.exp b/gcc/testsuite/gcc.dg/isan/isan.exp new file mode 100644 index 0000000..5274afc --- /dev/null +++ b/gcc/testsuite/gcc.dg/isan/isan.exp @@ -0,0 +1,36 @@ +# Copyright (C) 2013-2015 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp +load_lib ubsan-dg.exp + +# Initialize `dg'. +dg-init +ubsan_init + +# Main loop. +if [check_effective_target_fsanitize_undefined] { + gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/isan/*.c]] "" "" +} + +# All done. +ubsan_finish +dg-finish diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c index d23dabd..8d18cf1 100644 --- a/gcc/tree-ssa-reassoc.c +++ b/gcc/tree-ssa-reassoc.c @@ -2345,6 +2345,8 @@ optimize_range_tests_diff (enum tree_code opcode, tree type, mask = fold_build1 (BIT_NOT_EXPR, type, tem1); tem1 = fold_binary (MINUS_EXPR, type, fold_convert (type, rangei->exp), lowi); + if (tem1 == NULL_TREE) + return false; tem1 = fold_build2 (BIT_AND_EXPR, type, tem1, mask); lowj = build_int_cst (type, 0); if (update_range_test (rangei, rangej, NULL, 1, opcode, ops, tem1, diff --git a/gcc/tree.h b/gcc/tree.h index cb687d2..1967097 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -843,8 +843,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, /* True if an overflow is to be preserved for sanitization. */ #define TYPE_OVERFLOW_SANITIZED(TYPE) \ (INTEGRAL_TYPE_P (TYPE) \ - && !TYPE_OVERFLOW_WRAPS (TYPE) \ - && (flag_sanitize & SANITIZE_SI_OVERFLOW)) + && (flag_sanitize & (SANITIZE_SI_OVERFLOW | SANITIZE_UI_OVERFLOW))) /* True if pointer types have undefined overflow. */ #define POINTER_TYPE_OVERFLOW_UNDEFINED (flag_strict_overflow) diff --git a/gcc/ubsan.c b/gcc/ubsan.c index 7b0a3f1..144686e 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -1242,26 +1242,29 @@ ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype, ubsan_type_descriptor (lhstype), NULL_TREE, NULL_TREE); enum built_in_function fn_code; + bool uns_p = TYPE_UNSIGNED (lhstype); + unsigned sanitize_code = uns_p ? SANITIZE_SI_OVERFLOW | SANITIZE_UI_OVERFLOW + : SANITIZE_SI_OVERFLOW; switch (code) { case PLUS_EXPR: - fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW) + fn_code = (flag_sanitize_recover & sanitize_code) ? BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW : BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT; break; case MINUS_EXPR: - fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW) + fn_code = (flag_sanitize_recover & sanitize_code) ? BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW : BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW_ABORT; break; case MULT_EXPR: - fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW) + fn_code = (flag_sanitize_recover & sanitize_code) ? BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW : BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW_ABORT; break; case NEGATE_EXPR: - fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW) + fn_code = (flag_sanitize_recover & sanitize_code) ? BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW : BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW_ABORT; break; @@ -1961,6 +1964,7 @@ public: virtual bool gate (function *) { return flag_sanitize & (SANITIZE_NULL | SANITIZE_SI_OVERFLOW + | SANITIZE_UI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM | SANITIZE_ALIGNMENT | SANITIZE_NONNULL_ATTRIBUTE -- 2.7.4 From 7ff73c022a558042dfb4406afe213e26a007eb5c Mon Sep 17 00:00:00 2001 From: Ivan Baravy Date: Thu, 2 Nov 2017 16:02:53 +0300 Subject: [PATCH 14/16] Implement suppression list support for ISan. Change-Id: I41a8c572d30626caa45acf30758e00219b40bf03 --- gcc/testsuite/c-c++-common/isan/isan.supp | 3 ++ gcc/testsuite/c-c++-common/isan/suppressions.c | 46 +++++++++++++++++++++++++ libsanitizer/ubsan/ubsan_diag.cc | 47 ++++++++++++++++++++++++++ libsanitizer/ubsan/ubsan_diag.h | 2 ++ libsanitizer/ubsan/ubsan_flags.inc | 3 +- libsanitizer/ubsan/ubsan_handlers.cc | 7 ++++ 6 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/c-c++-common/isan/isan.supp create mode 100644 gcc/testsuite/c-c++-common/isan/suppressions.c diff --git a/gcc/testsuite/c-c++-common/isan/isan.supp b/gcc/testsuite/c-c++-common/isan/isan.supp new file mode 100644 index 0000000..dedd198 --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/isan.supp @@ -0,0 +1,3 @@ +# filter out matches from ISan output +function:bar +file:blah diff --git a/gcc/testsuite/c-c++-common/isan/suppressions.c b/gcc/testsuite/c-c++-common/isan/suppressions.c new file mode 100644 index 0000000..2735be8e --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/suppressions.c @@ -0,0 +1,46 @@ +/* { dg-do run } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow,signed-integer-overflow" } */ +/* { dg-set-target-env-var UBSAN_OPTIONS "suppressions_isan=$srcdir/c-c++-common/isan/isan.supp" } */ + +__attribute__((noinline, noclone)) +void foo () +{ + volatile unsigned int x = __UINT32_MAX__; + volatile unsigned int y = x + 1; +} + +__attribute__((noinline, noclone)) +void bar () +{ + volatile int a = __INT_MAX__; + volatile int b = a + 1; + + volatile unsigned int x = __UINT32_MAX__; + volatile unsigned int y = x + 1; +} + +__attribute__((noinline, noclone)) +void xyz () +{ + foo (); + bar (); +} + +int main () +{ + foo (); + bar (); + xyz (); + + for (int i = 0; i < 2; i++) + { + foo (); + bar (); + xyz (); + } + + return 0; +} + +/* { dg-output "suppressions.c:9:31: runtime error: unsigned integer overflow: 4294967295 \\+ 1 cannot be represented in type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */ +/* { dg-output "\[^\n\r]*suppressions.c:16:22: runtime error: signed integer overflow: 2147483647 \\+ 1 cannot be represented in type 'int'" } */ diff --git a/libsanitizer/ubsan/ubsan_diag.cc b/libsanitizer/ubsan/ubsan_diag.cc index ff04718..dac0937 100644 --- a/libsanitizer/ubsan/ubsan_diag.cc +++ b/libsanitizer/ubsan/ubsan_diag.cc @@ -382,20 +382,35 @@ ScopedReport::~ScopedReport() { } ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +ALIGNED(64) static char suppression_placeholder_isan[sizeof(SuppressionContext)]; +static bool isan_use_file_suppressions; +static bool isan_use_function_suppressions; static SuppressionContext *suppression_ctx = nullptr; +static SuppressionContext *suppression_ctx_isan = nullptr; static const char kVptrCheck[] = "vptr_check"; +static const char kFunctionCheck[] = "function"; +static const char kFileCheck[] = "file"; static const char *kSuppressionTypes[] = { #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName, #include "ubsan_checks.inc" #undef UBSAN_CHECK kVptrCheck, }; +static const char *kSuppressionTypesISan[] = { kFunctionCheck, kFileCheck }; void __ubsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); suppression_ctx = new (suppression_placeholder) // NOLINT SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); + CHECK_EQ(nullptr, suppression_ctx_isan); + suppression_ctx_isan = new (suppression_placeholder_isan) // NOLINT + SuppressionContext(kSuppressionTypesISan, ARRAY_SIZE(kSuppressionTypesISan)); + suppression_ctx_isan->ParseFromFile(flags()->suppressions_isan); + isan_use_file_suppressions = + suppression_ctx_isan->HasSuppressionType(kFileCheck); + isan_use_function_suppressions = + suppression_ctx_isan->HasSuppressionType(kFunctionCheck); } bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) { @@ -429,4 +444,36 @@ bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) { suppression_ctx->Match(AI.file, SuppType, &s); } +bool __ubsan::IsISanFileCheckSuppressed(SourceLocation *SLoc) { + InitAsStandaloneIfNecessary(); + if (LIKELY(!isan_use_file_suppressions)) + return false; + CHECK(suppression_ctx_isan); + Suppression *s; + const char *file_name = SLoc->getFilename(); + if (file_name && suppression_ctx_isan->Match(file_name, kFileCheck, &s)) + return true; + return false; +} + +bool __ubsan::IsISanFunctionCheckSuppressed(ReportOptions *Opts) { + InitAsStandaloneIfNecessary(); + if (LIKELY(!isan_use_function_suppressions)) + return false; + CHECK(suppression_ctx_isan); + SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(Opts->pc); + Suppression *s; + for (SymbolizedStack *cur = frames; cur; cur = cur->next) { + const char *function_name = cur->info.function; + if (!function_name) + continue; + if (suppression_ctx_isan->Match(function_name, kFunctionCheck, &s)) { + frames->ClearAll(); + return true; + } + } + frames->ClearAll(); + return false; +} + #endif // CAN_SANITIZE_UB diff --git a/libsanitizer/ubsan/ubsan_diag.h b/libsanitizer/ubsan/ubsan_diag.h index 3456aaa..7cce755 100644 --- a/libsanitizer/ubsan/ubsan_diag.h +++ b/libsanitizer/ubsan/ubsan_diag.h @@ -244,6 +244,8 @@ public: void InitializeSuppressions(); bool IsVptrCheckSuppressed(const char *TypeName); +bool IsISanFileCheckSuppressed(SourceLocation *SLoc); +bool IsISanFunctionCheckSuppressed(ReportOptions *Opts); // Sometimes UBSan runtime can know filename from handlers arguments, even if // debug info is missing. bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename); diff --git a/libsanitizer/ubsan/ubsan_flags.inc b/libsanitizer/ubsan/ubsan_flags.inc index 170777a..6125d44 100644 --- a/libsanitizer/ubsan/ubsan_flags.inc +++ b/libsanitizer/ubsan/ubsan_flags.inc @@ -19,6 +19,7 @@ UBSAN_FLAG(bool, halt_on_error, false, "Crash the program after printing the first error report") UBSAN_FLAG(bool, print_stacktrace, false, "Include full stacktrace into an error report") -UBSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") +UBSAN_FLAG(const char *, suppressions, "", "UBSan suppressions file name.") +UBSAN_FLAG(const char *, suppressions_isan, "", "ISan suppressions file name.") UBSAN_FLAG(bool, report_error_type, false, "Print specific error type instead of 'undefined-behavior' in summary.") diff --git a/libsanitizer/ubsan/ubsan_handlers.cc b/libsanitizer/ubsan/ubsan_handlers.cc index 0e343d3..ca99a49 100644 --- a/libsanitizer/ubsan/ubsan_handlers.cc +++ b/libsanitizer/ubsan/ubsan_handlers.cc @@ -30,6 +30,13 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) { // thread could have acquired it, but not yet printed the report. if (Opts.FromUnrecoverableHandler) return false; + // Check if report is explicitly disabled by user via suppressions file. + if (ET == ErrorType::UnsignedIntegerOverflow) { + if (IsISanFileCheckSuppressed(&SLoc)) + return true; + if (IsISanFunctionCheckSuppressed(&Opts)) + return true; + } return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename()); } -- 2.7.4 From 91dc6cda498f9cd7c608bd1494ddcd2aacee9e84 Mon Sep 17 00:00:00 2001 From: Denis Khalikov Date: Mon, 30 Oct 2017 19:12:50 +0300 Subject: [PATCH 15/16] [ISan] Fix issue with constexpr. The semantic of the constexpr does not allow us to convert POINTER type to INTERGER type inside constexpr. All ISAN instrumentation should be folded, but it's little bit tricky, in case we should convert INTEGER type back to POINTER type, because INTEGER type could not be assigned to POINTER type. Another issue is that some actual value of PARM_DECL could not be getting by "constexpr context" and could not be folded. So, just disable ISAN insrumentation and pointer conversions for constexpr semantic. In this case we can rely on current_function_decl while processing function, but also should handle constexpr with pointers: constexpr unsigned *pointer = ptr + index; Change-Id: I68eb660438a1acd881207219c3d72045c445dcb7 --- gcc/c-family/c-common.c | 14 ++++++++++++-- gcc/cp/parser.c | 10 ++++++++++ gcc/cp/typeck.c | 5 +++-- gcc/testsuite/g++.dg/isan/constexpr.C | 21 +++++++++++++++++++++ gcc/toplev.c | 7 +++++++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 22420bb..7068034 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -157,6 +157,8 @@ machine_mode c_default_pointer_mode = VOIDmode; */ +extern bool processing_constexpr_decl; + tree c_global_trees[CTI_MAX]; /* Switches common to the C front ends. */ @@ -4254,7 +4256,9 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, /* The result is a pointer of the same type that is being added. */ tree result_type = TREE_TYPE (ptrop); - if (flag_sanitize & SANITIZE_UI_OVERFLOW) + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && !((current_function_decl && DECL_LANG_FLAG_8 (current_function_decl)) + || processing_constexpr_decl)) { /* First, try to avoid FPs if INTOP is negative constant. */ if (tree_fits_shwi_p (intop)) @@ -4338,7 +4342,13 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, intop = wide_int_to_tree (TREE_TYPE (intop), intop); } - if (flag_sanitize & SANITIZE_UI_OVERFLOW) + /* Doing this for constexpr will cause an error, even without ISAN + instrumentation: ‘*(const char*)(((long unsigned int)ptr) + + ((long unsigned int)index))’ is not a constant expression. So, just disable + pointer convertion for constexpr. */ + if ((flag_sanitize & SANITIZE_UI_OVERFLOW) + && !((current_function_decl && DECL_LANG_FLAG_8 (current_function_decl)) + || processing_constexpr_decl)) { tree tmp = NULL_TREE; /* First, try to avoid FPs if INTOP is negative constant. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bb2d371..b66b7e1 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -266,6 +266,8 @@ static void cp_finalize_oacc_routine /* Variables. */ +extern bool processing_constexpr_decl; + /* The stream to which debugging output should be written. */ static FILE *cp_lexer_debug_stream; @@ -18399,6 +18401,7 @@ cp_parser_init_declarator (cp_parser* parser, bool range_for_decl_p = false; bool saved_default_arg_ok_p = parser->default_arg_ok_p; location_t tmp_init_loc = UNKNOWN_LOCATION; + processing_constexpr_decl = false; /* Gather the attributes that were provided with the decl-specifiers. */ @@ -18688,6 +18691,13 @@ cp_parser_init_declarator (cp_parser* parser, arguments. So right here we only handle the latter. */ if (!member_p && processing_template_decl) start_lambda_scope (decl); + + /* Save info about constexpr declaration, in case we have + constexpr unsigned *p = ptr + index, current_function_decl + does not work for us. */ + if (decl && DECL_DECLARED_CONSTEXPR_P (decl)) + processing_constexpr_decl = true; + initializer = cp_parser_initializer (parser, &is_direct_init, &is_non_constant_init); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index b5a9dd0..fdaba65 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -5164,8 +5164,9 @@ cp_build_binary_op (location_t location, } if ((flag_sanitize & SANITIZE_UI_OVERFLOW) - && (doing_plus || doing_minus || doing_mul) - && !processing_template_decl) + && (doing_plus || doing_minus || doing_mul) && !processing_template_decl + && !(current_function_decl + && DECL_DECLARED_CONSTEXPR_P (current_function_decl))) { op0 = cp_save_expr (op0); op1 = cp_save_expr (op1); diff --git a/gcc/testsuite/g++.dg/isan/constexpr.C b/gcc/testsuite/g++.dg/isan/constexpr.C index 4896396..76c5e62 100644 --- a/gcc/testsuite/g++.dg/isan/constexpr.C +++ b/gcc/testsuite/g++.dg/isan/constexpr.C @@ -6,3 +6,24 @@ constexpr int foo (int i) { return std::__lg (i); } + +constexpr const char *string = "string"; + +constexpr unsigned int str2int(const char *str, int h = 0) { + return !str[h] ? 5381 : (str2int(str, h + 1) * 33) ^ str[h]; +} + +constexpr unsigned int arr[] = {1, 2, 3, 4, 5}; + +constexpr unsigned int index = 1; + +class A +{ + static constexpr const unsigned int *ptr = arr + index; +}; + +int main () +{ + constexpr unsigned int result_value = str2int (string); + A a; +} diff --git a/gcc/toplev.c b/gcc/toplev.c index 8979d26..3e0b54a 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -101,6 +101,13 @@ static void compile_file (void); /* True if we don't need a backend (e.g. preprocessing only). */ static bool no_backend; +/* True if processing constexpr declaration. + Could not be use to verify function declaration. + Only usable for constexpr pointer. + Example: + constexpr unsigned *pointer = ptr + index. */ +bool processing_constexpr_decl = false; + /* Length of line when printing switch values. */ #define MAX_LINE 75 -- 2.7.4 From 2fdbd3fb5ab97bcb33a8d1ae9950125ca544e10c Mon Sep 17 00:00:00 2001 From: Denis Khalikov Date: Tue, 7 Nov 2017 19:10:03 +0300 Subject: [PATCH 16/16] [ISan] Fix ICE with ISan and -ftree-loop-vectorize In case we want to vectorize the loop, we can not rely only on TREE_OVERFLOW flag, while folding the INTEGER_CST, which represents the step of vectorization. We still should check TYPE_OVERFLOW_WRAPS flag instead TYPE_OVERFLOW_SANITIZED flag, because the step could be already marked as TREE_OVERFLOW == 1. Change-Id: I1288b7e3b587c5773b184636bdfdada168b8941f --- gcc/fold-const.c | 5 +++-- gcc/testsuite/c-c++-common/isan/loop-vect.c | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/isan/loop-vect.c diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 17ff640..23ee11f 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -550,8 +550,9 @@ fold_negate_expr (location_t loc, tree t) if (TREE_OVERFLOW (tem) == TREE_OVERFLOW (t) || (ANY_INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_TRAPS (type) - && !TYPE_OVERFLOW_SANITIZED (type)) - || (flag_sanitize & (SANITIZE_SI_OVERFLOW | SANITIZE_UI_OVERFLOW)) == 0) + && TYPE_OVERFLOW_WRAPS (type)) + || (flag_sanitize & (SANITIZE_SI_OVERFLOW | SANITIZE_UI_OVERFLOW)) + == 0) return tem; break; diff --git a/gcc/testsuite/c-c++-common/isan/loop-vect.c b/gcc/testsuite/c-c++-common/isan/loop-vect.c new file mode 100644 index 0000000..3944652 --- /dev/null +++ b/gcc/testsuite/c-c++-common/isan/loop-vect.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-fsanitize=unsigned-integer-overflow" } */ + +typedef struct { + int r; + int i; +} kiss_fft_cpx; + +typedef struct { + int inmem[0]; +} TonalityAnalysisState; + +float a; +kiss_fft_cpx b[0]; +TonalityAnalysisState c; + +void foo() { + int i = 0; + for (; i < 40; i++) + b[-i].i = a * c.inmem[i]; +} -- 2.7.4