1from __future__ import absolute_import
2from __future__ import print_function
3
4# System modules
5from distutils.version import LooseVersion, StrictVersion
6from functools import wraps
7import inspect
8import os
9import platform
10import re
11import sys
12import tempfile
13
14# Third-party modules
15import six
16import unittest2
17
18# LLDB modules
19import use_lldb_suite
20
21import lldb
22from . import configuration
23from . import test_categories
24from lldbsuite.test_event.event_builder import EventBuilder
25from lldbsuite.support import funcutils
26from lldbsuite.test import lldbplatform
27from lldbsuite.test import lldbplatformutil
28
29
30class DecorateMode:
31    Skip, Xfail = range(2)
32
33
34# You can use no_match to reverse the test of the conditional that is used to match keyword
35# arguments in the skip / xfail decorators.  If oslist=["windows", "linux"] skips windows
36# and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows
37# or linux.
38class no_match:
39
40    def __init__(self, item):
41        self.item = item
42
43
44def _check_expected_version(comparison, expected, actual):
45    def fn_leq(x, y): return x <= y
46
47    def fn_less(x, y): return x < y
48
49    def fn_geq(x, y): return x >= y
50
51    def fn_greater(x, y): return x > y
52
53    def fn_eq(x, y): return x == y
54
55    def fn_neq(x, y): return x != y
56
57    op_lookup = {
58        "==": fn_eq,
59        "=": fn_eq,
60        "!=": fn_neq,
61        "<>": fn_neq,
62        ">": fn_greater,
63        "<": fn_less,
64        ">=": fn_geq,
65        "<=": fn_leq
66    }
67    expected_str = '.'.join([str(x) for x in expected])
68    actual_str = '.'.join([str(x) for x in actual])
69
70    return op_lookup[comparison](
71        LooseVersion(actual_str),
72        LooseVersion(expected_str))
73
74
75def _match_decorator_property(expected, actual):
76    if actual is None or expected is None:
77        return True
78
79    if isinstance(expected, no_match):
80        return not _match_decorator_property(expected.item, actual)
81    elif isinstance(expected, (re._pattern_type,) + six.string_types):
82        return re.search(expected, actual) is not None
83    elif hasattr(expected, "__iter__"):
84        return any([x is not None and _match_decorator_property(x, actual)
85                    for x in expected])
86    else:
87        return expected == actual
88
89
90def expectedFailure(expected_fn, bugnumber=None):
91    def expectedFailure_impl(func):
92        if isinstance(func, type) and issubclass(func, unittest2.TestCase):
93            raise Exception(
94                "Decorator can only be used to decorate a test method")
95
96        @wraps(func)
97        def wrapper(*args, **kwargs):
98            self = args[0]
99            if funcutils.requires_self(expected_fn):
100                xfail_reason = expected_fn(self)
101            else:
102                xfail_reason = expected_fn()
103            if xfail_reason is not None:
104                if configuration.results_formatter_object is not None:
105                    # Mark this test as expected to fail.
106                    configuration.results_formatter_object.handle_event(
107                        EventBuilder.event_for_mark_test_expected_failure(self))
108                xfail_func = unittest2.expectedFailure(func)
109                xfail_func(*args, **kwargs)
110            else:
111                func(*args, **kwargs)
112        return wrapper
113    # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
114    # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
115    # the first way, the first argument will be the actual function because decorators are
116    # weird like that.  So this is basically a check that says "which syntax was the original
117    # function decorated with?"
118    if six.callable(bugnumber):
119        return expectedFailure_impl(bugnumber)
120    else:
121        return expectedFailure_impl
122
123
124def skipTestIfFn(expected_fn, bugnumber=None):
125    def skipTestIfFn_impl(func):
126        if isinstance(func, type) and issubclass(func, unittest2.TestCase):
127            raise Exception(
128                "@skipTestIfFn can only be used to decorate a test method")
129
130        @wraps(func)
131        def wrapper(*args, **kwargs):
132            self = args[0]
133            if funcutils.requires_self(expected_fn):
134                reason = expected_fn(self)
135            else:
136                reason = expected_fn()
137
138            if reason is not None:
139                self.skipTest(reason)
140            else:
141                func(*args, **kwargs)
142        return wrapper
143
144    # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
145    # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
146    # the first way, the first argument will be the actual function because decorators are
147    # weird like that.  So this is basically a check that says "how was the
148    # decorator used"
149    if six.callable(bugnumber):
150        return skipTestIfFn_impl(bugnumber)
151    else:
152        return skipTestIfFn_impl
153
154
155def _decorateTest(mode,
156                  bugnumber=None, oslist=None, hostoslist=None,
157                  compiler=None, compiler_version=None,
158                  archs=None, triple=None,
159                  debug_info=None,
160                  swig_version=None, py_version=None,
161                  macos_version=None,
162                  remote=None):
163    def fn(self):
164        skip_for_os = _match_decorator_property(
165            lldbplatform.translate(oslist), self.getPlatform())
166        skip_for_hostos = _match_decorator_property(
167            lldbplatform.translate(hostoslist),
168            lldbplatformutil.getHostPlatform())
169        skip_for_compiler = _match_decorator_property(
170            compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version)
171        skip_for_arch = _match_decorator_property(
172            archs, self.getArchitecture())
173        skip_for_debug_info = _match_decorator_property(
174            debug_info, self.getDebugInfo())
175        skip_for_triple = _match_decorator_property(
176            triple, lldb.DBG.GetSelectedPlatform().GetTriple())
177        skip_for_remote = _match_decorator_property(
178            remote, lldb.remote_platform is not None)
179
180        skip_for_swig_version = (
181            swig_version is None) or (
182            not hasattr(
183                lldb,
184                'swig_version')) or (
185                _check_expected_version(
186                    swig_version[0],
187                    swig_version[1],
188                    lldb.swig_version))
189        skip_for_py_version = (
190            py_version is None) or _check_expected_version(
191            py_version[0], py_version[1], sys.version_info)
192        skip_for_macos_version = (macos_version is None) or (
193            _check_expected_version(
194                macos_version[0],
195                macos_version[1],
196                platform.mac_ver()[0]))
197
198        # For the test to be skipped, all specified (e.g. not None) parameters must be True.
199        # An unspecified parameter means "any", so those are marked skip by default.  And we skip
200        # the final test if all conditions are True.
201        conditions = [(oslist, skip_for_os, "target o/s"),
202                      (hostoslist, skip_for_hostos, "host o/s"),
203                      (compiler, skip_for_compiler, "compiler or version"),
204                      (archs, skip_for_arch, "architecture"),
205                      (debug_info, skip_for_debug_info, "debug info format"),
206                      (triple, skip_for_triple, "target triple"),
207                      (swig_version, skip_for_swig_version, "swig version"),
208                      (py_version, skip_for_py_version, "python version"),
209                      (macos_version, skip_for_macos_version, "macOS version"),
210                      (remote, skip_for_remote, "platform locality (remote/local)")]
211        reasons = []
212        final_skip_result = True
213        for this_condition in conditions:
214            final_skip_result = final_skip_result and this_condition[1]
215            if this_condition[0] is not None and this_condition[1]:
216                reasons.append(this_condition[2])
217        reason_str = None
218        if final_skip_result:
219            mode_str = {
220                DecorateMode.Skip: "skipping",
221                DecorateMode.Xfail: "xfailing"}[mode]
222            if len(reasons) > 0:
223                reason_str = ",".join(reasons)
224                reason_str = "{} due to the following parameter(s): {}".format(
225                    mode_str, reason_str)
226            else:
227                reason_str = "{} unconditionally"
228            if bugnumber is not None and not six.callable(bugnumber):
229                reason_str = reason_str + " [" + str(bugnumber) + "]"
230        return reason_str
231
232    if mode == DecorateMode.Skip:
233        return skipTestIfFn(fn, bugnumber)
234    elif mode == DecorateMode.Xfail:
235        return expectedFailure(fn, bugnumber)
236    else:
237        return None
238
239# provide a function to xfail on defined oslist, compiler version, and archs
240# if none is specified for any argument, that argument won't be checked and thus means for all
241# for example,
242# @expectedFailureAll, xfail for all platform/compiler/arch,
243# @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture
244# @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386
245
246
247def expectedFailureAll(bugnumber=None,
248                       oslist=None, hostoslist=None,
249                       compiler=None, compiler_version=None,
250                       archs=None, triple=None,
251                       debug_info=None,
252                       swig_version=None, py_version=None,
253                       macos_version=None,
254                       remote=None):
255    return _decorateTest(DecorateMode.Xfail,
256                         bugnumber=bugnumber,
257                         oslist=oslist, hostoslist=hostoslist,
258                         compiler=compiler, compiler_version=compiler_version,
259                         archs=archs, triple=triple,
260                         debug_info=debug_info,
261                         swig_version=swig_version, py_version=py_version,
262                         macos_version=None,
263                         remote=remote)
264
265
266# provide a function to skip on defined oslist, compiler version, and archs
267# if none is specified for any argument, that argument won't be checked and thus means for all
268# for example,
269# @skipIf, skip for all platform/compiler/arch,
270# @skipIf(compiler='gcc'), skip for gcc on all platform/architecture
271# @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386
272def skipIf(bugnumber=None,
273           oslist=None, hostoslist=None,
274           compiler=None, compiler_version=None,
275           archs=None, triple=None,
276           debug_info=None,
277           swig_version=None, py_version=None,
278           macos_version=None,
279           remote=None):
280    return _decorateTest(DecorateMode.Skip,
281                         bugnumber=bugnumber,
282                         oslist=oslist, hostoslist=hostoslist,
283                         compiler=compiler, compiler_version=compiler_version,
284                         archs=archs, triple=triple,
285                         debug_info=debug_info,
286                         swig_version=swig_version, py_version=py_version,
287                         macos_version=macos_version,
288                         remote=remote)
289
290
291def _skip_for_android(reason, api_levels, archs):
292    def impl(obj):
293        result = lldbplatformutil.match_android_device(
294            obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels)
295        return reason if result else None
296    return impl
297
298
299def add_test_categories(cat):
300    """Add test categories to a TestCase method"""
301    cat = test_categories.validate(cat, True)
302
303    def impl(func):
304        if isinstance(func, type) and issubclass(func, unittest2.TestCase):
305            raise Exception(
306                "@add_test_categories can only be used to decorate a test method")
307
308        # Update or set the categories attribute. For instance methods, the
309        # attribute must be set on the actual function.
310        func_for_attr = func
311        if inspect.ismethod(func_for_attr):
312            func_for_attr = func.__func__
313        if hasattr(func_for_attr, "categories"):
314            cat.extend(func_for_attr.categories)
315        setattr(func_for_attr, "categories", cat)
316
317        return func
318
319    return impl
320
321
322def benchmarks_test(func):
323    """Decorate the item as a benchmarks test."""
324    def should_skip_benchmarks_test():
325        return "benchmarks test"
326
327    # Mark this function as such to separate them from the regular tests.
328    result = skipTestIfFn(should_skip_benchmarks_test)(func)
329    result.__benchmarks_test__ = True
330    return result
331
332
333def no_debug_info_test(func):
334    """Decorate the item as a test what don't use any debug info. If this annotation is specified
335       then the test runner won't generate a separate test for each debug info format. """
336    if isinstance(func, type) and issubclass(func, unittest2.TestCase):
337        raise Exception(
338            "@no_debug_info_test can only be used to decorate a test method")
339
340    @wraps(func)
341    def wrapper(self, *args, **kwargs):
342        return func(self, *args, **kwargs)
343
344    # Mark this function as such to separate them from the regular tests.
345    wrapper.__no_debug_info_test__ = True
346    return wrapper
347
348
349def debugserver_test(func):
350    """Decorate the item as a debugserver test."""
351    def should_skip_debugserver_test():
352        return "debugserver tests" if configuration.dont_do_debugserver_test else None
353    return skipTestIfFn(should_skip_debugserver_test)(func)
354
355
356def llgs_test(func):
357    """Decorate the item as a lldb-server test."""
358    def should_skip_llgs_tests():
359        return "llgs tests" if configuration.dont_do_llgs_test else None
360    return skipTestIfFn(should_skip_llgs_tests)(func)
361
362
363def not_remote_testsuite_ready(func):
364    """Decorate the item as a test which is not ready yet for remote testsuite."""
365    def is_remote():
366        return "Not ready for remote testsuite" if lldb.remote_platform else None
367    return skipTestIfFn(is_remote)(func)
368
369
370def expectedFailureOS(
371        oslist,
372        bugnumber=None,
373        compilers=None,
374        debug_info=None,
375        archs=None):
376    return expectedFailureAll(
377        oslist=oslist,
378        bugnumber=bugnumber,
379        compiler=compilers,
380        archs=archs,
381        debug_info=debug_info)
382
383
384def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None):
385    # For legacy reasons, we support both "darwin" and "macosx" as OS X
386    # triples.
387    return expectedFailureOS(
388        lldbplatform.darwin_all,
389        bugnumber,
390        compilers,
391        debug_info=debug_info)
392
393
394def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None):
395    """ Mark a test as xfail for Android.
396
397    Arguments:
398        bugnumber - The LLVM pr associated with the problem.
399        api_levels - A sequence of numbers specifying the Android API levels
400            for which a test is expected to fail. None means all API level.
401        arch - A sequence of architecture names specifying the architectures
402            for which a test is expected to fail. None means all architectures.
403    """
404    return expectedFailure(
405        _skip_for_android(
406            "xfailing on android",
407            api_levels,
408            archs),
409        bugnumber)
410
411# Flakey tests get two chances to run. If they fail the first time round, the result formatter
412# makes sure it is run one more time.
413
414
415def expectedFlakey(expected_fn, bugnumber=None):
416    def expectedFailure_impl(func):
417        @wraps(func)
418        def wrapper(*args, **kwargs):
419            self = args[0]
420            if expected_fn(self):
421                # Send event marking test as explicitly eligible for rerunning.
422                if configuration.results_formatter_object is not None:
423                    # Mark this test as rerunnable.
424                    configuration.results_formatter_object.handle_event(
425                        EventBuilder.event_for_mark_test_rerun_eligible(self))
426            func(*args, **kwargs)
427        return wrapper
428    # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
429    # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
430    # the first way, the first argument will be the actual function because decorators are
431    # weird like that.  So this is basically a check that says "which syntax was the original
432    # function decorated with?"
433    if six.callable(bugnumber):
434        return expectedFailure_impl(bugnumber)
435    else:
436        return expectedFailure_impl
437
438
439def expectedFlakeyDwarf(bugnumber=None):
440    def fn(self):
441        return self.getDebugInfo() == "dwarf"
442    return expectedFlakey(fn, bugnumber)
443
444
445def expectedFlakeyDsym(bugnumber=None):
446    def fn(self):
447        return self.getDebugInfo() == "dwarf"
448    return expectedFlakey(fn, bugnumber)
449
450
451def expectedFlakeyOS(oslist, bugnumber=None, compilers=None):
452    def fn(self):
453        return (self.getPlatform() in oslist and
454                self.expectedCompiler(compilers))
455    return expectedFlakey(fn, bugnumber)
456
457
458def expectedFlakeyDarwin(bugnumber=None, compilers=None):
459    # For legacy reasons, we support both "darwin" and "macosx" as OS X
460    # triples.
461    return expectedFlakeyOS(
462        lldbplatformutil.getDarwinOSTriples(),
463        bugnumber,
464        compilers)
465
466
467def expectedFlakeyFreeBSD(bugnumber=None, compilers=None):
468    return expectedFlakeyOS(['freebsd'], bugnumber, compilers)
469
470
471def expectedFlakeyLinux(bugnumber=None, compilers=None):
472    return expectedFlakeyOS(['linux'], bugnumber, compilers)
473
474
475def expectedFlakeyNetBSD(bugnumber=None, compilers=None):
476    return expectedFlakeyOS(['netbsd'], bugnumber, compilers)
477
478
479def expectedFlakeyCompiler(compiler, compiler_version=None, bugnumber=None):
480    if compiler_version is None:
481        compiler_version = ['=', None]
482
483    def fn(self):
484        return compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version)
485    return expectedFlakey(fn, bugnumber)
486
487# @expectedFlakeyClang('bugnumber', ['<=', '3.4'])
488
489
490def expectedFlakeyClang(bugnumber=None, compiler_version=None):
491    return expectedFlakeyCompiler('clang', compiler_version, bugnumber)
492
493# @expectedFlakeyGcc('bugnumber', ['<=', '3.4'])
494
495
496def expectedFlakeyGcc(bugnumber=None, compiler_version=None):
497    return expectedFlakeyCompiler('gcc', compiler_version, bugnumber)
498
499
500def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None):
501    return expectedFlakey(
502        _skip_for_android(
503            "flakey on android",
504            api_levels,
505            archs),
506        bugnumber)
507
508
509def skipIfRemote(func):
510    """Decorate the item to skip tests if testing remotely."""
511    def is_remote():
512        return "skip on remote platform" if lldb.remote_platform else None
513    return skipTestIfFn(is_remote)(func)
514
515
516def skipIfNoSBHeaders(func):
517    """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers."""
518    def are_sb_headers_missing():
519        if lldbplatformutil.getHostPlatform() == 'darwin':
520            header = os.path.join(
521                os.environ["LLDB_LIB_DIR"],
522                'LLDB.framework',
523                'Versions',
524                'Current',
525                'Headers',
526                'LLDB.h')
527            if os.path.exists(header):
528                return None
529
530        header = os.path.join(
531            os.environ["LLDB_SRC"],
532            "include",
533            "lldb",
534            "API",
535            "LLDB.h")
536        if not os.path.exists(header):
537            return "skip because LLDB.h header not found"
538        return None
539
540    return skipTestIfFn(are_sb_headers_missing)(func)
541
542
543def skipIfiOSSimulator(func):
544    """Decorate the item to skip tests that should be skipped on the iOS Simulator."""
545    def is_ios_simulator():
546        return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None
547    return skipTestIfFn(is_ios_simulator)(func)
548
549def skipIfiOS(func):
550    return skipIfPlatform(["ios"])(func)
551
552def skipIftvOS(func):
553    return skipIfPlatform(["tvos"])(func)
554
555def skipIfwatchOS(func):
556    return skipIfPlatform(["watchos"])(func)
557
558def skipIfbridgeOS(func):
559    return skipIfPlatform(["bridgeos"])(func)
560
561def skipIfDarwinEmbedded(func):
562    """Decorate the item to skip tests that should be skipped on Darwin armv7/arm64 targets."""
563    return skipIfPlatform(
564        lldbplatform.translate(
565            lldbplatform.darwin_embedded))(func)
566
567def skipIfFreeBSD(func):
568    """Decorate the item to skip tests that should be skipped on FreeBSD."""
569    return skipIfPlatform(["freebsd"])(func)
570
571
572def skipIfNetBSD(func):
573    """Decorate the item to skip tests that should be skipped on NetBSD."""
574    return skipIfPlatform(["netbsd"])(func)
575
576
577def skipIfDarwin(func):
578    """Decorate the item to skip tests that should be skipped on Darwin."""
579    return skipIfPlatform(
580        lldbplatform.translate(
581            lldbplatform.darwin_all))(func)
582
583
584def skipIfLinux(func):
585    """Decorate the item to skip tests that should be skipped on Linux."""
586    return skipIfPlatform(["linux"])(func)
587
588
589def skipIfWindows(func):
590    """Decorate the item to skip tests that should be skipped on Windows."""
591    return skipIfPlatform(["windows"])(func)
592
593
594def skipUnlessWindows(func):
595    """Decorate the item to skip tests that should be skipped on any non-Windows platform."""
596    return skipUnlessPlatform(["windows"])(func)
597
598
599def skipUnlessDarwin(func):
600    """Decorate the item to skip tests that should be skipped on any non Darwin platform."""
601    return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func)
602
603
604def skipUnlessGoInstalled(func):
605    """Decorate the item to skip tests when no Go compiler is available."""
606
607    def is_go_missing(self):
608        compiler = self.getGoCompilerVersion()
609        if not compiler:
610            return "skipping because go compiler not found"
611        match_version = re.search(r"(\d+\.\d+(\.\d+)?)", compiler)
612        if not match_version:
613            # Couldn't determine version.
614            return "skipping because go version could not be parsed out of {}".format(
615                compiler)
616        else:
617            min_strict_version = StrictVersion("1.4.0")
618            compiler_strict_version = StrictVersion(match_version.group(1))
619            if compiler_strict_version < min_strict_version:
620                return "skipping because available version ({}) does not meet minimum required version ({})".format(
621                    compiler_strict_version, min_strict_version)
622        return None
623    return skipTestIfFn(is_go_missing)(func)
624
625
626def skipIfHostIncompatibleWithRemote(func):
627    """Decorate the item to skip tests if binaries built on this host are incompatible."""
628
629    def is_host_incompatible_with_remote(self):
630        host_arch = self.getLldbArchitecture()
631        host_platform = lldbplatformutil.getHostPlatform()
632        target_arch = self.getArchitecture()
633        target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform()
634        if not (target_arch == 'x86_64' and host_arch ==
635                'i386') and host_arch != target_arch:
636            return "skipping because target %s is not compatible with host architecture %s" % (
637                target_arch, host_arch)
638        if target_platform != host_platform:
639            return "skipping because target is %s but host is %s" % (
640                target_platform, host_platform)
641        if lldbplatformutil.match_android_device(target_arch):
642            return "skipping because target is android"
643        return None
644    return skipTestIfFn(is_host_incompatible_with_remote)(func)
645
646
647def skipIfPlatform(oslist):
648    """Decorate the item to skip tests if running on one of the listed platforms."""
649    # This decorator cannot be ported to `skipIf` yet because it is used on entire
650    # classes, which `skipIf` explicitly forbids.
651    return unittest2.skipIf(lldbplatformutil.getPlatform() in oslist,
652                            "skip on %s" % (", ".join(oslist)))
653
654
655def skipUnlessPlatform(oslist):
656    """Decorate the item to skip tests unless running on one of the listed platforms."""
657    # This decorator cannot be ported to `skipIf` yet because it is used on entire
658    # classes, which `skipIf` explicitly forbids.
659    return unittest2.skipUnless(lldbplatformutil.getPlatform() in oslist,
660                                "requires one of %s" % (", ".join(oslist)))
661
662
663def skipIfTargetAndroid(api_levels=None, archs=None):
664    """Decorator to skip tests when the target is Android.
665
666    Arguments:
667        api_levels - The API levels for which the test should be skipped. If
668            it is None, then the test will be skipped for all API levels.
669        arch - A sequence of architecture names specifying the architectures
670            for which a test is skipped. None means all architectures.
671    """
672    return skipTestIfFn(
673        _skip_for_android(
674            "skipping for android",
675            api_levels,
676            archs))
677
678
679def skipUnlessThreadSanitizer(func):
680    """Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
681
682    def is_compiler_clang_with_thread_sanitizer(self):
683        compiler_path = self.getCompiler()
684        compiler = os.path.basename(compiler_path)
685        if not compiler.startswith("clang"):
686            return "Test requires clang as compiler"
687        if lldbplatformutil.getPlatform() == 'windows':
688            return "TSAN tests not compatible with 'windows'"
689        # rdar://28659145 - TSAN tests don't look like they're supported on i386
690        if self.getArchitecture() == 'i386' and platform.system() == 'Darwin':
691            return "TSAN tests not compatible with i386 targets"
692        f = tempfile.NamedTemporaryFile()
693        cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name)
694        if os.popen(cmd).close() is not None:
695            return None  # The compiler cannot compile at all, let's *not* skip the test
696        cmd = "echo 'int main() {}' | %s -fsanitize=thread -x c -o %s -" % (compiler_path, f.name)
697        if os.popen(cmd).close() is not None:
698            return "Compiler cannot compile with -fsanitize=thread"
699        return None
700    return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func)
701
702def skipUnlessUndefinedBehaviorSanitizer(func):
703    """Decorate the item to skip test unless -fsanitize=undefined is supported."""
704
705    def is_compiler_clang_with_ubsan(self):
706        # Write out a temp file which exhibits UB.
707        inputf = tempfile.NamedTemporaryFile(suffix='.c')
708        inputf.write('int main() { int x = 0; return x / x; }\n')
709        inputf.flush()
710
711        # We need to write out the object into a named temp file for inspection.
712        outputf = tempfile.NamedTemporaryFile()
713
714        # Try to compile with ubsan turned on.
715        cmd = '%s -fsanitize=undefined %s -o %s' % (self.getCompiler(), inputf.name, outputf.name)
716        if os.popen(cmd).close() is not None:
717            return "Compiler cannot compile with -fsanitize=undefined"
718
719        # Check that we actually see ubsan instrumentation in the binary.
720        cmd = 'nm %s' % outputf.name
721        with os.popen(cmd) as nm_output:
722            if '___ubsan_handle_divrem_overflow' not in nm_output.read():
723                return "Division by zero instrumentation is missing"
724
725        # Find the ubsan dylib.
726        # FIXME: This check should go away once compiler-rt gains support for __ubsan_on_report.
727        cmd = '%s -fsanitize=undefined -x c - -o - -### 2>&1' % self.getCompiler()
728        with os.popen(cmd) as cc_output:
729            driver_jobs = cc_output.read()
730            m = re.search(r'"([^"]+libclang_rt.ubsan_osx_dynamic.dylib)"', driver_jobs)
731            if not m:
732                return "Could not find the ubsan dylib used by the driver"
733            ubsan_dylib = m.group(1)
734
735        # Check that the ubsan dylib has special monitor hooks.
736        cmd = 'nm -gU %s' % ubsan_dylib
737        with os.popen(cmd) as nm_output:
738            syms = nm_output.read()
739            if '___ubsan_on_report' not in syms:
740                return "Missing ___ubsan_on_report"
741            if '___ubsan_get_current_report_data' not in syms:
742                return "Missing ___ubsan_get_current_report_data"
743
744        # OK, this dylib + compiler works for us.
745        return None
746
747    return skipTestIfFn(is_compiler_clang_with_ubsan)(func)
748
749def skipUnlessAddressSanitizer(func):
750    """Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
751
752    def is_compiler_with_address_sanitizer(self):
753        compiler_path = self.getCompiler()
754        compiler = os.path.basename(compiler_path)
755        f = tempfile.NamedTemporaryFile()
756        if lldbplatformutil.getPlatform() == 'windows':
757            return "ASAN tests not compatible with 'windows'"
758        cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name)
759        if os.popen(cmd).close() is not None:
760            return None  # The compiler cannot compile at all, let's *not* skip the test
761        cmd = "echo 'int main() {}' | %s -fsanitize=address -x c -o %s -" % (compiler_path, f.name)
762        if os.popen(cmd).close() is not None:
763            return "Compiler cannot compile with -fsanitize=address"
764        return None
765    return skipTestIfFn(is_compiler_with_address_sanitizer)(func)
766