Use a special test launcher that links the sanitize runtime library directly
This commit is contained in:
parent
ba7a6e8106
commit
788f09e855
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@ build
|
|||||||
README.html
|
README.html
|
||||||
linux-package
|
linux-package
|
||||||
logo/*.iconset
|
logo/*.iconset
|
||||||
|
test-launcher
|
||||||
|
|||||||
48
.travis.yml
48
.travis.yml
@ -6,7 +6,7 @@ matrix:
|
|||||||
group: beta
|
group: beta
|
||||||
sudo: false
|
sudo: false
|
||||||
env:
|
env:
|
||||||
- CC=gcc ASANLIB=libasan.so.0 ASAN_ARG=--asan
|
- CC=gcc SANITIZE_ARG=--sanitize
|
||||||
language: python
|
language: python
|
||||||
python: "3.5"
|
python: "3.5"
|
||||||
addons:
|
addons:
|
||||||
@ -24,7 +24,25 @@ matrix:
|
|||||||
group: beta
|
group: beta
|
||||||
sudo: false
|
sudo: false
|
||||||
env:
|
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
|
language: python
|
||||||
python: "3.5"
|
python: "3.5"
|
||||||
addons:
|
addons:
|
||||||
@ -45,6 +63,13 @@ matrix:
|
|||||||
language: generic
|
language: generic
|
||||||
env: USE_BREW=1 BUILD_PKG=1
|
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: |
|
install: |
|
||||||
set -e
|
set -e
|
||||||
if [[ "$RUN_FLAKE" == "1" ]]; then pip install flake8; fi
|
if [[ "$RUN_FLAKE" == "1" ]]; then pip install flake8; fi
|
||||||
@ -59,7 +84,7 @@ install: |
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
wget -O glfw-3.2.1.zip https://github.com/glfw/glfw/archive/3.2.1.zip
|
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
|
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
|
cmake -DBUILD_SHARED_LIBS=ON -DGLFW_BUILD_EXAMPLES=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_DOCS=OFF -DCMAKE_INSTALL_PREFIX=$HOME/glfw
|
||||||
make
|
make
|
||||||
@ -67,17 +92,18 @@ install: |
|
|||||||
cd ..
|
cd ..
|
||||||
fi
|
fi
|
||||||
pkg-config --cflags glfw3
|
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
|
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:
|
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:
|
script:
|
||||||
- LD_PRELOAD=$ASANLIB $PYTHON setup.py test
|
- ./test-launcher
|
||||||
- if [[ "$RUN_FLAKE" == "1" ]]; then flake8 --count .; fi
|
- if [[ "$RUN_FLAKE" == "1" ]]; then flake8 --count .; fi
|
||||||
- if [[ "$BUILD_PKG" == "1" ]]; then $PYTHON setup.py linux-package; fi
|
- if [[ "$BUILD_PKG" == "1" ]]; then $PYTHON setup.py linux-package; fi
|
||||||
|
|||||||
@ -140,7 +140,7 @@ static PyStructSequence_Field gm_fields[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static PyStructSequence_Desc gm_desc = {"GlpyhMetrics", NULL, gm_fields, 8};
|
static PyStructSequence_Desc gm_desc = {"GlpyhMetrics", NULL, gm_fields, 8};
|
||||||
static PyTypeObject GlpyhMetricsType = {0};
|
static PyTypeObject GlpyhMetricsType = {{{0}}};
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
glyph_metrics(Face *self) {
|
glyph_metrics(Face *self) {
|
||||||
@ -167,7 +167,7 @@ static PyStructSequence_Field bm_fields[] = {
|
|||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
static PyStructSequence_Desc bm_desc = {"Bitmap", NULL, bm_fields, 7};
|
static PyStructSequence_Desc bm_desc = {"Bitmap", NULL, bm_fields, 7};
|
||||||
static PyTypeObject BitmapType = {0};
|
static PyTypeObject BitmapType = {{{0}}};
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
bitmap(Face *self) {
|
bitmap(Face *self) {
|
||||||
|
|||||||
@ -95,7 +95,7 @@ index_type historybuf_push(HistoryBuf *self) {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
historybuf_resize(HistoryBuf *self, index_type lines) {
|
historybuf_resize(HistoryBuf *self, index_type lines) {
|
||||||
HistoryBuf t = {0};
|
HistoryBuf t = {{0}};
|
||||||
t.xnum=self->xnum;
|
t.xnum=self->xnum;
|
||||||
t.ynum=lines;
|
t.ynum=lines;
|
||||||
if (t.ynum > 0 && t.ynum != self->ynum) {
|
if (t.ynum > 0 && t.ynum != self->ynum) {
|
||||||
|
|||||||
@ -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; }
|
if (!PyObject_TypeCheck(y, &LineBuf_Type)) { PyErr_SetString(PyExc_TypeError, "Not a LineBuf object"); return NULL; }
|
||||||
LineBuf *other = (LineBuf*)y;
|
LineBuf *other = (LineBuf*)y;
|
||||||
if (other->xnum != self->xnum) { PyErr_SetString(PyExc_ValueError, "LineBuf has a different number of columns"); return NULL; }
|
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;
|
sl.xnum = self->xnum; ol.xnum = other->xnum;
|
||||||
|
|
||||||
for (index_type i = 0; i < MIN(self->ynum, other->ynum); i++) {
|
for (index_type i = 0; i < MIN(self->ynum, other->ynum); i++) {
|
||||||
|
|||||||
62
setup.py
62
setup.py
@ -53,7 +53,7 @@ def cc_version():
|
|||||||
ver = tuple(map(int, ver))
|
ver = tuple(map(int, ver))
|
||||||
except Exception:
|
except Exception:
|
||||||
ver = (0, 0)
|
ver = (0, 0)
|
||||||
return ver
|
return cc, ver
|
||||||
|
|
||||||
|
|
||||||
def get_python_flags(cflags):
|
def get_python_flags(cflags):
|
||||||
@ -88,36 +88,43 @@ def get_python_flags(cflags):
|
|||||||
return libs
|
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
|
global cflags, ldflags, cc, ldpaths
|
||||||
native_optimizations = native_optimizations and not asan and not debug
|
native_optimizations = native_optimizations and not sanitize and not debug
|
||||||
ccver = cc_version()
|
cc, ccver = cc_version()
|
||||||
|
print('CC:', cc, ccver)
|
||||||
stack_protector = '-fstack-protector'
|
stack_protector = '-fstack-protector'
|
||||||
if ccver >= (4, 9):
|
if ccver >= (4, 9) and cc == 'gcc':
|
||||||
stack_protector += '-strong'
|
stack_protector += '-strong'
|
||||||
missing_braces = ''
|
missing_braces = ''
|
||||||
if ccver < (5, 2):
|
if ccver < (5, 2) and cc == 'gcc':
|
||||||
missing_braces = '-Wno-missing-braces'
|
missing_braces = '-Wno-missing-braces'
|
||||||
cc = os.environ.get('CC', 'gcc')
|
optimize = '-ggdb' if debug or sanitize else '-O3'
|
||||||
optimize = '-O3'
|
sanitize_args = get_sanitize_args(cc, ccver) if sanitize else set()
|
||||||
if debug or asan:
|
|
||||||
optimize = '-ggdb'
|
|
||||||
if asan:
|
|
||||||
optimize += ' -fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer'
|
|
||||||
cflags = os.environ.get(
|
cflags = os.environ.get(
|
||||||
'OVERRIDE_CFLAGS', (
|
'OVERRIDE_CFLAGS', (
|
||||||
'-Wextra -Wno-missing-field-initializers -Wall -std=c99 -D_XOPEN_SOURCE=700'
|
'-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(
|
).format(
|
||||||
optimize, stack_protector, missing_braces, '-march=native'
|
optimize, ' '.join(sanitize_args), stack_protector, missing_braces, '-march=native'
|
||||||
if native_optimizations else ''
|
if native_optimizations else ''
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
cflags = shlex.split(cflags
|
cflags = shlex.split(cflags
|
||||||
) + shlex.split(sysconfig.get_config_var('CCSHARED'))
|
) + shlex.split(sysconfig.get_config_var('CCSHARED'))
|
||||||
ldflags = os.environ.get(
|
ldflags = os.environ.get(
|
||||||
'OVERRIDE_LDFLAGS', '-Wall ' +
|
'OVERRIDE_LDFLAGS', '-Wall ' + ' '.join(sanitize_args) + ('' if debug else ' -O3')
|
||||||
('-fsanitize=address -fsanitize=undefined' if asan else ('' if debug else '-O3'))
|
|
||||||
)
|
)
|
||||||
ldflags = shlex.split(ldflags)
|
ldflags = shlex.split(ldflags)
|
||||||
cflags += shlex.split(os.environ.get('CFLAGS', ''))
|
cflags += shlex.split(os.environ.get('CFLAGS', ''))
|
||||||
@ -230,11 +237,13 @@ def option_parser():
|
|||||||
help='Build extension modules with debugging symbols'
|
help='Build extension modules with debugging symbols'
|
||||||
)
|
)
|
||||||
p.add_argument(
|
p.add_argument(
|
||||||
'--asan',
|
'--sanitize',
|
||||||
default=False,
|
default=False,
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Turn on address sanitization to detect memory access errors. Note that if you do turn it on,'
|
help='Turn on sanitization to detect memory access errors and undefined behavior. Note that if you do turn it on,'
|
||||||
' you have to run kitty with the environment variable LD_PRELOAD=/usr/lib/libasan.so'
|
' 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(
|
p.add_argument(
|
||||||
'--prefix',
|
'--prefix',
|
||||||
@ -268,7 +277,7 @@ def find_c_files():
|
|||||||
|
|
||||||
|
|
||||||
def build(args, native_optimizations=True):
|
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(
|
compile_c_extension(
|
||||||
'kitty/fast_data_types', args.incremental, *find_c_files()
|
'kitty/fast_data_types', args.incremental, *find_c_files()
|
||||||
)
|
)
|
||||||
@ -281,6 +290,18 @@ def safe_makedirs(path):
|
|||||||
pass
|
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): # {{{
|
def package(args, for_bundle=False): # {{{
|
||||||
ddir = args.prefix
|
ddir = args.prefix
|
||||||
libdir = os.path.join(ddir, 'lib', 'kitty')
|
libdir = os.path.join(ddir, 'lib', 'kitty')
|
||||||
@ -360,6 +381,7 @@ def main():
|
|||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
if args.action == 'build':
|
if args.action == 'build':
|
||||||
build(args)
|
build(args)
|
||||||
|
build_test_launcher(args)
|
||||||
elif args.action == 'test':
|
elif args.action == 'test':
|
||||||
os.execlp(
|
os.execlp(
|
||||||
sys.executable, sys.executable, os.path.join(base, 'test.py')
|
sys.executable, sys.executable, os.path.join(base, 'test.py')
|
||||||
|
|||||||
13
test-launcher.c
Normal file
13
test-launcher.c
Normal 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);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user