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