2022-12-28 12:22:14 +01:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# Copyright (c) 2020 The Bitcoin Core developers
|
|
|
|
# Distributed under the MIT software license, see the accompanying
|
|
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
'''
|
|
|
|
Test script for symbol-check.py
|
|
|
|
'''
|
2021-03-13 17:27:11 +01:00
|
|
|
import os
|
2022-12-28 12:22:14 +01:00
|
|
|
import subprocess
|
2023-06-04 19:34:54 +02:00
|
|
|
from typing import List
|
2022-12-28 12:22:14 +01:00
|
|
|
import unittest
|
|
|
|
|
2023-06-04 19:34:54 +02:00
|
|
|
from utils import determine_wellknown_cmd
|
|
|
|
|
|
|
|
def call_symbol_check(cc: List[str], source, executable, options):
|
2023-05-13 17:23:21 +02:00
|
|
|
# This should behave the same as AC_TRY_LINK, so arrange well-known flags
|
|
|
|
# in the same order as autoconf would.
|
|
|
|
#
|
|
|
|
# See the definitions for ac_link in autoconf's lib/autoconf/c.m4 file for
|
|
|
|
# reference.
|
|
|
|
env_flags: List[str] = []
|
|
|
|
for var in ['CFLAGS', 'CPPFLAGS', 'LDFLAGS']:
|
|
|
|
env_flags += filter(None, os.environ.get(var, '').split(' '))
|
|
|
|
|
|
|
|
subprocess.run([*cc,source,'-o',executable] + env_flags + options, check=True)
|
2022-12-28 12:22:14 +01:00
|
|
|
p = subprocess.run(['./contrib/devtools/symbol-check.py',executable], stdout=subprocess.PIPE, universal_newlines=True)
|
2021-03-13 17:27:11 +01:00
|
|
|
os.remove(source)
|
|
|
|
os.remove(executable)
|
2022-12-28 12:22:14 +01:00
|
|
|
return (p.returncode, p.stdout.rstrip())
|
|
|
|
|
2023-06-04 19:34:54 +02:00
|
|
|
def get_machine(cc: List[str]):
|
|
|
|
p = subprocess.run([*cc,'-dumpmachine'], stdout=subprocess.PIPE, universal_newlines=True)
|
|
|
|
return p.stdout.rstrip()
|
|
|
|
|
2022-12-28 12:22:14 +01:00
|
|
|
class TestSymbolChecks(unittest.TestCase):
|
|
|
|
def test_ELF(self):
|
|
|
|
source = 'test1.c'
|
|
|
|
executable = 'test1'
|
2023-06-04 19:34:54 +02:00
|
|
|
cc = determine_wellknown_cmd('CC', 'gcc')
|
|
|
|
|
2023-06-03 15:36:53 +02:00
|
|
|
# there's no way to do this test for ARM at the moment; we build for
|
|
|
|
# ARM in a glibc 2.31 envinonment and we allow all symbols from 2.28.
|
|
|
|
if 'arm' in get_machine(cc):
|
|
|
|
self.skipTest("test not available for 32-bit ARM")
|
|
|
|
|
2022-12-28 12:22:14 +01:00
|
|
|
# -lutil is part of the libc6 package so a safe bet that it's installed
|
|
|
|
# it's also out of context enough that it's unlikely to ever become a real dependency
|
|
|
|
source = 'test2.c'
|
|
|
|
executable = 'test2'
|
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
|
|
|
#include <utmp.h>
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
login(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, ['-lutil']),
|
2023-05-13 17:23:21 +02:00
|
|
|
(1, executable + ': libutil.so.1 is not in ALLOWED_LIBRARIES!\n' +
|
2022-12-28 12:22:14 +01:00
|
|
|
executable + ': failed LIBRARY_DEPENDENCIES'))
|
|
|
|
|
Merge bitcoin/bitcoin#22645: scripts: prevent GCC optimising test symbols in test-symbol-check
5449d44e37982fcd5251fd47873c5f7d34c39fc9 scripts: prevent GCC optimising test symbols in test-symbol-check (fanquake)
Pull request description:
I noticed in #22381 that when the test-symbol-check target was being built with Clang and run in the CI it would fail due to using a too-new version of `pow` (used [here](https://github.com/bitcoin/bitcoin/blob/d67330d11245b11fbdd5e2dd5343ee451186931e/contrib/devtools/test-symbol-check.py#L85)). Our CIs use Focal (glibc 2.31) and the version of `pow` was the optimized version introduced in [glibc 2.29](https://lwn.net/Articles/778286/):
```bash
* Optimized generic exp, exp2, log, log2, pow, sinf, cosf, sincosf and tanf.
```
This made sense, except for that if it was failing when built using Clang, why hadn't it also been failing when being built with GCC?
Turns out GCC is optimizing away that call to `pow` at all optimization levels, including `-O0`, see: https://godbolt.org/z/53MhzMxT7, and this has been the case forever, or at least since GCC 5.x. Clang on the other hand, will only optimize away the `pow` call at `-O1` and `-O2`, not `-O0`: https://godbolt.org/z/Wbnqj3q6c. Thus when this test was built with Clang (we don't pass `-O` so we default to `-O0`) it was failing in the CI environment, because it would actually have a call to the "new" `pow`.
Avoid this issue by using a symbol that won't be optimized away, or that we are unlikely to ever have versioning issues with.
ACKs for top commit:
laanwj:
ACK 5449d44e37982fcd5251fd47873c5f7d34c39fc9
Tree-SHA512: 3a26c5c3a5f2905fd0dd90892470e241ba625c0af3be2629d06d5da3a97534c1d6a55b796bbdd41e2e6a26a8fab7d981b98c45d4238565b0eb7edf3c5da02007
2021-08-18 17:16:02 +02:00
|
|
|
# finally, check a simple conforming binary
|
2022-12-28 12:22:14 +01:00
|
|
|
source = 'test3.c'
|
|
|
|
executable = 'test3'
|
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
Merge bitcoin/bitcoin#22645: scripts: prevent GCC optimising test symbols in test-symbol-check
5449d44e37982fcd5251fd47873c5f7d34c39fc9 scripts: prevent GCC optimising test symbols in test-symbol-check (fanquake)
Pull request description:
I noticed in #22381 that when the test-symbol-check target was being built with Clang and run in the CI it would fail due to using a too-new version of `pow` (used [here](https://github.com/bitcoin/bitcoin/blob/d67330d11245b11fbdd5e2dd5343ee451186931e/contrib/devtools/test-symbol-check.py#L85)). Our CIs use Focal (glibc 2.31) and the version of `pow` was the optimized version introduced in [glibc 2.29](https://lwn.net/Articles/778286/):
```bash
* Optimized generic exp, exp2, log, log2, pow, sinf, cosf, sincosf and tanf.
```
This made sense, except for that if it was failing when built using Clang, why hadn't it also been failing when being built with GCC?
Turns out GCC is optimizing away that call to `pow` at all optimization levels, including `-O0`, see: https://godbolt.org/z/53MhzMxT7, and this has been the case forever, or at least since GCC 5.x. Clang on the other hand, will only optimize away the `pow` call at `-O1` and `-O2`, not `-O0`: https://godbolt.org/z/Wbnqj3q6c. Thus when this test was built with Clang (we don't pass `-O` so we default to `-O0`) it was failing in the CI environment, because it would actually have a call to the "new" `pow`.
Avoid this issue by using a symbol that won't be optimized away, or that we are unlikely to ever have versioning issues with.
ACKs for top commit:
laanwj:
ACK 5449d44e37982fcd5251fd47873c5f7d34c39fc9
Tree-SHA512: 3a26c5c3a5f2905fd0dd90892470e241ba625c0af3be2629d06d5da3a97534c1d6a55b796bbdd41e2e6a26a8fab7d981b98c45d4238565b0eb7edf3c5da02007
2021-08-18 17:16:02 +02:00
|
|
|
#include <stdio.h>
|
2022-12-28 12:22:14 +01:00
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
Merge bitcoin/bitcoin#22645: scripts: prevent GCC optimising test symbols in test-symbol-check
5449d44e37982fcd5251fd47873c5f7d34c39fc9 scripts: prevent GCC optimising test symbols in test-symbol-check (fanquake)
Pull request description:
I noticed in #22381 that when the test-symbol-check target was being built with Clang and run in the CI it would fail due to using a too-new version of `pow` (used [here](https://github.com/bitcoin/bitcoin/blob/d67330d11245b11fbdd5e2dd5343ee451186931e/contrib/devtools/test-symbol-check.py#L85)). Our CIs use Focal (glibc 2.31) and the version of `pow` was the optimized version introduced in [glibc 2.29](https://lwn.net/Articles/778286/):
```bash
* Optimized generic exp, exp2, log, log2, pow, sinf, cosf, sincosf and tanf.
```
This made sense, except for that if it was failing when built using Clang, why hadn't it also been failing when being built with GCC?
Turns out GCC is optimizing away that call to `pow` at all optimization levels, including `-O0`, see: https://godbolt.org/z/53MhzMxT7, and this has been the case forever, or at least since GCC 5.x. Clang on the other hand, will only optimize away the `pow` call at `-O1` and `-O2`, not `-O0`: https://godbolt.org/z/Wbnqj3q6c. Thus when this test was built with Clang (we don't pass `-O` so we default to `-O0`) it was failing in the CI environment, because it would actually have a call to the "new" `pow`.
Avoid this issue by using a symbol that won't be optimized away, or that we are unlikely to ever have versioning issues with.
ACKs for top commit:
laanwj:
ACK 5449d44e37982fcd5251fd47873c5f7d34c39fc9
Tree-SHA512: 3a26c5c3a5f2905fd0dd90892470e241ba625c0af3be2629d06d5da3a97534c1d6a55b796bbdd41e2e6a26a8fab7d981b98c45d4238565b0eb7edf3c5da02007
2021-08-18 17:16:02 +02:00
|
|
|
printf("42");
|
|
|
|
return 0;
|
2022-12-28 12:22:14 +01:00
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
Merge bitcoin/bitcoin#22645: scripts: prevent GCC optimising test symbols in test-symbol-check
5449d44e37982fcd5251fd47873c5f7d34c39fc9 scripts: prevent GCC optimising test symbols in test-symbol-check (fanquake)
Pull request description:
I noticed in #22381 that when the test-symbol-check target was being built with Clang and run in the CI it would fail due to using a too-new version of `pow` (used [here](https://github.com/bitcoin/bitcoin/blob/d67330d11245b11fbdd5e2dd5343ee451186931e/contrib/devtools/test-symbol-check.py#L85)). Our CIs use Focal (glibc 2.31) and the version of `pow` was the optimized version introduced in [glibc 2.29](https://lwn.net/Articles/778286/):
```bash
* Optimized generic exp, exp2, log, log2, pow, sinf, cosf, sincosf and tanf.
```
This made sense, except for that if it was failing when built using Clang, why hadn't it also been failing when being built with GCC?
Turns out GCC is optimizing away that call to `pow` at all optimization levels, including `-O0`, see: https://godbolt.org/z/53MhzMxT7, and this has been the case forever, or at least since GCC 5.x. Clang on the other hand, will only optimize away the `pow` call at `-O1` and `-O2`, not `-O0`: https://godbolt.org/z/Wbnqj3q6c. Thus when this test was built with Clang (we don't pass `-O` so we default to `-O0`) it was failing in the CI environment, because it would actually have a call to the "new" `pow`.
Avoid this issue by using a symbol that won't be optimized away, or that we are unlikely to ever have versioning issues with.
ACKs for top commit:
laanwj:
ACK 5449d44e37982fcd5251fd47873c5f7d34c39fc9
Tree-SHA512: 3a26c5c3a5f2905fd0dd90892470e241ba625c0af3be2629d06d5da3a97534c1d6a55b796bbdd41e2e6a26a8fab7d981b98c45d4238565b0eb7edf3c5da02007
2021-08-18 17:16:02 +02:00
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, []),
|
2022-12-28 12:22:14 +01:00
|
|
|
(0, ''))
|
|
|
|
|
|
|
|
def test_MACHO(self):
|
|
|
|
source = 'test1.c'
|
|
|
|
executable = 'test1'
|
2023-06-04 19:34:54 +02:00
|
|
|
cc = determine_wellknown_cmd('CC', 'clang')
|
2022-12-28 12:22:14 +01:00
|
|
|
|
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
|
|
|
#include <expat.h>
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
XML_ExpatVersion();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
''')
|
|
|
|
|
2023-06-04 19:34:54 +02:00
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, ['-lexpat', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']),
|
2022-12-28 12:22:14 +01:00
|
|
|
(1, 'libexpat.1.dylib is not in ALLOWED_LIBRARIES!\n' +
|
2023-05-13 17:32:47 +02:00
|
|
|
f'{executable}: failed DYNAMIC_LIBRARIES MIN_OS SDK'))
|
2022-12-28 12:22:14 +01:00
|
|
|
|
|
|
|
source = 'test2.c'
|
|
|
|
executable = 'test2'
|
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
|
|
|
#include <CoreGraphics/CoreGraphics.h>
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
CGMainDisplayID();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
2023-06-04 19:34:54 +02:00
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, ['-framework', 'CoreGraphics', '-Wl,-platform_version','-Wl,macos', '-Wl,11.4', '-Wl,11.4']),
|
2023-05-13 17:32:47 +02:00
|
|
|
(1, f'{executable}: failed MIN_OS SDK'))
|
|
|
|
|
|
|
|
source = 'test3.c'
|
|
|
|
executable = 'test3'
|
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
2023-06-04 19:34:54 +02:00
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,-platform_version','-Wl,macos', '-Wl,10.15', '-Wl,11.4']),
|
2023-05-13 17:32:47 +02:00
|
|
|
(1, f'{executable}: failed SDK'))
|
2022-12-28 12:22:14 +01:00
|
|
|
|
2020-12-09 15:33:31 +01:00
|
|
|
def test_PE(self):
|
|
|
|
source = 'test1.c'
|
|
|
|
executable = 'test1.exe'
|
2023-06-04 19:34:54 +02:00
|
|
|
cc = determine_wellknown_cmd('CC', 'x86_64-w64-mingw32-gcc')
|
2020-12-09 15:33:31 +01:00
|
|
|
|
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
|
|
|
#include <pdh.h>
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
PdhConnectMachineA(NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
2023-05-13 17:32:47 +02:00
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, ['-lpdh', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']),
|
2020-12-09 15:33:31 +01:00
|
|
|
(1, 'pdh.dll is not in ALLOWED_LIBRARIES!\n' +
|
|
|
|
executable + ': failed DYNAMIC_LIBRARIES'))
|
|
|
|
|
|
|
|
source = 'test2.c'
|
|
|
|
executable = 'test2.exe'
|
2023-05-13 17:32:47 +02:00
|
|
|
|
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, ['-Wl,--major-subsystem-version', '-Wl,9', '-Wl,--minor-subsystem-version', '-Wl,9']),
|
|
|
|
(1, executable + ': failed SUBSYSTEM_VERSION'))
|
|
|
|
|
|
|
|
source = 'test3.c'
|
|
|
|
executable = 'test3.exe'
|
2020-12-09 15:33:31 +01:00
|
|
|
with open(source, 'w', encoding="utf8") as f:
|
|
|
|
f.write('''
|
2022-03-13 09:23:07 +01:00
|
|
|
#include <combaseapi.h>
|
2020-12-09 15:33:31 +01:00
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
CoFreeUnusedLibrariesEx(0,0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
2023-05-13 17:32:47 +02:00
|
|
|
self.assertEqual(call_symbol_check(cc, source, executable, ['-lole32', '-Wl,--major-subsystem-version', '-Wl,6', '-Wl,--minor-subsystem-version', '-Wl,1']),
|
2020-12-09 15:33:31 +01:00
|
|
|
(0, ''))
|
|
|
|
|
|
|
|
|
2022-12-28 12:22:14 +01:00
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest.main()
|