Use a special test launcher that links the sanitize runtime library directly

This commit is contained in:
Kovid Goyal 2017-05-15 10:18:59 +05:30
parent ba7a6e8106
commit 788f09e855
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 97 additions and 35 deletions

1
.gitignore vendored
View File

@ -7,3 +7,4 @@ build
README.html
linux-package
logo/*.iconset
test-launcher

View File

@ -6,7 +6,7 @@ matrix:
group: beta
sudo: false
env:
- CC=gcc ASANLIB=libasan.so.0 ASAN_ARG=--asan
- CC=gcc SANITIZE_ARG=--sanitize
language: python
python: "3.5"
addons:
@ -24,7 +24,25 @@ matrix:
group: beta
sudo: false
env:
- CC=clang RUN_FLAKE=1 BUILD_PKG=1
- CC=clang SANITIZE_ARG=--sanitize
language: python
python: "3.5"
addons:
apt:
packages:
- libfontconfig1-dev
- libglew-dev
- libxi-dev
- libxrandr-dev
- libxinerama-dev
- libxcursor-dev
- os: linux
dist: trusty
group: beta
sudo: false
env:
- RUN_FLAKE=1 BUILD_PKG=1
language: python
python: "3.5"
addons:
@ -45,6 +63,13 @@ matrix:
language: generic
env: USE_BREW=1 BUILD_PKG=1
env:
global:
- PYTHON=python3
- PKG_CONFIG_PATH=$HOME/glfw/lib/pkgconfig:$PKG_CONFIG_PATH
- LD_LIBRARY_PATH=$HOME/glfw/lib:$LD_LIBRARY_PATH
- ASAN_OPTIONS=leak_check_at_exit=0
install: |
set -e
if [[ "$RUN_FLAKE" == "1" ]]; then pip install flake8; fi
@ -59,7 +84,7 @@ install: |
fi
else
wget -O glfw-3.2.1.zip https://github.com/glfw/glfw/archive/3.2.1.zip
unzip glfw-3.2.1.zip
unzip -q glfw-3.2.1.zip
cd glfw-3.2.1
cmake -DBUILD_SHARED_LIBS=ON -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_DOCS=OFF -DCMAKE_INSTALL_PREFIX=$HOME/glfw
make
@ -67,17 +92,18 @@ install: |
cd ..
fi
pkg-config --cflags glfw3
if [[ "$TRAVIS_OS_NAME" != 'osx' ]]; then
PLIB=$(ldd `which python` | grep libpython | cut -d ' ' -f 3)
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`dirname $PLIB`
fi
set +e
env:
global:
- PKG_CONFIG_PATH=$HOME/glfw/lib/pkgconfig
- LD_LIBRARY_PATH=$HOME/glfw/lib
- ASAN_OPTIONS=leak_check_at_exit=0
- PYTHON=python3
before_script:
- $PYTHON setup.py build --debug $ASAN_ARG;
- echo $LD_LIBRARY_PATH
- $PYTHON setup.py build --debug $SANITIZE_ARG;
- if [[ "$TRAVIS_OS_NAME" != 'osx' ]]; then ldd ./test-launcher `which $PYTHON`; fi
script:
- LD_PRELOAD=$ASANLIB $PYTHON setup.py test
- ./test-launcher
- if [[ "$RUN_FLAKE" == "1" ]]; then flake8 --count .; fi
- if [[ "$BUILD_PKG" == "1" ]]; then $PYTHON setup.py linux-package; fi

View File

@ -140,7 +140,7 @@ static PyStructSequence_Field gm_fields[] = {
};
static PyStructSequence_Desc gm_desc = {"GlpyhMetrics", NULL, gm_fields, 8};
static PyTypeObject GlpyhMetricsType = {0};
static PyTypeObject GlpyhMetricsType = {{{0}}};
static PyObject*
glyph_metrics(Face *self) {
@ -167,7 +167,7 @@ static PyStructSequence_Field bm_fields[] = {
{NULL}
};
static PyStructSequence_Desc bm_desc = {"Bitmap", NULL, bm_fields, 7};
static PyTypeObject BitmapType = {0};
static PyTypeObject BitmapType = {{{0}}};
static PyObject*
bitmap(Face *self) {

View File

@ -95,7 +95,7 @@ index_type historybuf_push(HistoryBuf *self) {
bool
historybuf_resize(HistoryBuf *self, index_type lines) {
HistoryBuf t = {0};
HistoryBuf t = {{0}};
t.xnum=self->xnum;
t.ynum=lines;
if (t.ynum > 0 && t.ynum != self->ynum) {

View File

@ -423,7 +423,7 @@ copy_old(LineBuf *self, PyObject *y) {
if (!PyObject_TypeCheck(y, &LineBuf_Type)) { PyErr_SetString(PyExc_TypeError, "Not a LineBuf object"); return NULL; }
LineBuf *other = (LineBuf*)y;
if (other->xnum != self->xnum) { PyErr_SetString(PyExc_ValueError, "LineBuf has a different number of columns"); return NULL; }
Line sl = {0}, ol = {0};
Line sl = {{0}}, ol = {{0}};
sl.xnum = self->xnum; ol.xnum = other->xnum;
for (index_type i = 0; i < MIN(self->ynum, other->ynum); i++) {

View File

@ -53,7 +53,7 @@ def cc_version():
ver = tuple(map(int, ver))
except Exception:
ver = (0, 0)
return ver
return cc, ver
def get_python_flags(cflags):
@ -88,36 +88,43 @@ def get_python_flags(cflags):
return libs
def init_env(debug=False, asan=False, native_optimizations=True):
def get_sanitize_args(cc, ccver):
sanitize_args = set()
sanitize_args.add('-fno-omit-frame-pointer')
sanitize_args.add('-fsanitize=address')
if (cc == 'gcc' and ccver >= (5, 0)) or cc == 'clang':
sanitize_args.add('-fsanitize=undefined')
# if cc == 'gcc' or (cc == 'clang' and ccver >= (4, 2)):
# sanitize_args.add('-fno-sanitize-recover=all')
return sanitize_args
def init_env(debug=False, sanitize=False, native_optimizations=True):
global cflags, ldflags, cc, ldpaths
native_optimizations = native_optimizations and not asan and not debug
ccver = cc_version()
native_optimizations = native_optimizations and not sanitize and not debug
cc, ccver = cc_version()
print('CC:', cc, ccver)
stack_protector = '-fstack-protector'
if ccver >= (4, 9):
if ccver >= (4, 9) and cc == 'gcc':
stack_protector += '-strong'
missing_braces = ''
if ccver < (5, 2):
if ccver < (5, 2) and cc == 'gcc':
missing_braces = '-Wno-missing-braces'
cc = os.environ.get('CC', 'gcc')
optimize = '-O3'
if debug or asan:
optimize = '-ggdb'
if asan:
optimize += ' -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer'
optimize = '-ggdb' if debug or sanitize else '-O3'
sanitize_args = get_sanitize_args(cc, ccver) if sanitize else set()
cflags = os.environ.get(
'OVERRIDE_CFLAGS', (
'-Wextra -Wno-missing-field-initializers -Wall -std=c99 -D_XOPEN_SOURCE=700'
' -pedantic-errors -Werror {} -DNDEBUG -fwrapv {} {} -pipe {}'
' -pedantic-errors -Werror {} {} -DNDEBUG -fwrapv {} {} -pipe {}'
).format(
optimize, stack_protector, missing_braces, '-march=native'
optimize, ' '.join(sanitize_args), stack_protector, missing_braces, '-march=native'
if native_optimizations else ''
)
)
cflags = shlex.split(cflags
) + shlex.split(sysconfig.get_config_var('CCSHARED'))
ldflags = os.environ.get(
'OVERRIDE_LDFLAGS', '-Wall ' +
('-fsanitize=address -fsanitize=undefined' if asan else ('' if debug else '-O3'))
'OVERRIDE_LDFLAGS', '-Wall ' + ' '.join(sanitize_args) + ('' if debug else ' -O3')
)
ldflags = shlex.split(ldflags)
cflags += shlex.split(os.environ.get('CFLAGS', ''))
@ -230,11 +237,13 @@ def option_parser():
help='Build extension modules with debugging symbols'
)
p.add_argument(
'--asan',
'--sanitize',
default=False,
action='store_true',
help='Turn on address sanitization to detect memory access errors. Note that if you do turn it on,'
' you have to run kitty with the environment variable LD_PRELOAD=/usr/lib/libasan.so'
help='Turn on sanitization to detect memory access errors and undefined behavior. Note that if you do turn it on,'
' a special executable will be built for running the test suite. If you want to run normal kitty'
' with sanitization, use LD_PRELOAD=libasan.so (for gcc) and'
' LD_PRELOAD=/usr/lib/clang/4.0.0/lib/linux/libclang_rt.asan-x86_64.so (for clang, changing path as appropriate).'
)
p.add_argument(
'--prefix',
@ -268,7 +277,7 @@ def find_c_files():
def build(args, native_optimizations=True):
init_env(args.debug, args.asan, native_optimizations)
init_env(args.debug, args.sanitize, native_optimizations)
compile_c_extension(
'kitty/fast_data_types', args.incremental, *find_c_files()
)
@ -281,6 +290,18 @@ def safe_makedirs(path):
pass
def build_test_launcher(args):
cc, ccver = cc_version()
cflags = '-g -Wall -Werror -fpie'.split()
pylib = get_python_flags(cflags)
sanitize_lib = (['-lasan'] if cc == 'gcc' else []) if args.sanitize else []
cflags.extend(get_sanitize_args(cc, ccver) if args.sanitize else [])
cmd = [cc] + cflags + [
'test-launcher.c', '-o', 'test-launcher',
] + sanitize_lib + pylib
run_tool(cmd)
def package(args, for_bundle=False): # {{{
ddir = args.prefix
libdir = os.path.join(ddir, 'lib', 'kitty')
@ -360,6 +381,7 @@ def main():
os.chdir(os.path.dirname(os.path.abspath(__file__)))
if args.action == 'build':
build(args)
build_test_launcher(args)
elif args.action == 'test':
os.execlp(
sys.executable, sys.executable, os.path.join(base, 'test.py')

13
test-launcher.c Normal file
View File

@ -0,0 +1,13 @@
/*
* linux-launcher.c
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include <Python.h>
int main(int argc, char *argv[]) {
wchar_t *wargv[2] = {L"kitty-test", L"test.py"};
return Py_Main(2, wargv);
}