Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix symbol visibility issues, add test for it #1359

Merged
merged 4 commits into from
Mar 13, 2025

Conversation

hebasto
Copy link
Member

@hebasto hebasto commented Jun 26, 2023

Closes #1181.

Catches the actual symbol visibility issue.

Replaces #1135.

@hebasto
Copy link
Member Author

hebasto commented Jun 27, 2023

Rebased on top of the merged #1356.

@hebasto hebasto force-pushed the 230626-visibility branch from f816729 to d7b1cea Compare July 13, 2023 15:53
@hebasto
Copy link
Member Author

hebasto commented Jul 13, 2023

Rebased f816729 -> d7b1cea (pr1359.02 -> pr1359.03) due to the conflict with #1313.

@hebasto hebasto force-pushed the 230626-visibility branch from d7b1cea to be7ccb9 Compare July 13, 2023 16:56
@hebasto hebasto marked this pull request as draft July 13, 2023 17:36
@hebasto hebasto force-pushed the 230626-visibility branch from be7ccb9 to 5e37264 Compare July 13, 2023 17:47
@hebasto hebasto marked this pull request as ready for review July 13, 2023 17:47
@hebasto hebasto marked this pull request as draft August 31, 2023 14:35
@hebasto hebasto marked this pull request as ready for review February 12, 2024 18:31
@hebasto
Copy link
Member Author

hebasto commented Feb 12, 2024

@maflcko

Is it possible for a Cirrus persistent worker to do not override environment variables set with the ENV command in the Dockerfile?

@maflcko
Copy link
Contributor

maflcko commented Feb 13, 2024

Maybe --env-file drops ENV?

@hebasto
Copy link
Member Author

hebasto commented Apr 23, 2024

Rebased to resolve conflicts.

@hebasto
Copy link
Member Author

hebasto commented Aug 25, 2024

#1595 (comment):

This reminds me that we should move forward with #1359.

Agreed.

Rebased and ready to move forward :)

@hebasto hebasto marked this pull request as draft October 16, 2024 13:07
@hebasto hebasto force-pushed the 230626-visibility branch 2 times, most recently from f2a6941 to 4f64b9f Compare October 16, 2024 14:01
@hebasto hebasto marked this pull request as ready for review October 16, 2024 14:34
Copy link
Contributor

@real-or-random real-or-random left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script can still be simplified. Let me suggest a refactored version later.


def check_PE_exported_functions(library, expected_exports) -> bool:
ok: bool = True
for function in library.exported_functions:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading the docs, I believe that .exported_functions is from the abstract Binary class, and [entry.name for entry in library.get_export()] may give the better result for PE because it includes non-function exports? See https://lief.re/doc/latest/formats/pe/python.html#export-entry

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggested approach returns the same list of symbols on the master branch. Incorporated as a potentially superior one.


def check_MACHO_exported_functions(library, expected_exports) -> bool:
ok: bool = True
for function in library.exported_functions:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After reading the docs, I believe that .exported_functions is from the abstract Binary class, and .exported_symbols may give a better result for Mach-O because it includes non-function exports?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggested approach returns the same list of symbols on the master branch. Incorporated as a potentially superior one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, just checking: You're saying that this change didn't make a difference, right? So it still finds only exported functions and not exported variables?

(And I have the same question for PE.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, just checking: You're saying that this change didn't make a difference, right?

Correct.

So it still finds only exported functions and not exported variables?

With the reverted second commit, both variants catch the same local variables:

./tools/symbol-check.py: In .libs/libsecp256k1.dylib: Unexpected exported symbols: {'secp256k1_pre_g', 'secp256k1_pre_g_128', 'secp256k1_ecmult_gen_prec_table'}

(And I have the same question for PE.)

With the reverted second commit, both variants do not catch local variables.

For more details, please refer to:

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, that means that the LIEF API is a bit unexpected. Or we don't understand it.

  • For Mach-O, exported_functions is the same as exported_symbols. Both include variables, but I'd expect the former to include only functions.
  • For PE, there doesn't seem to be a way to find exported variables. By the way, importing variables is rare, but the ellswift example and benchmark import the variable secp256k1_ellswift_xdh_hash_function_bip324, so at least we test this in CI. And thus we can be sure that the variables are actually exported in PE, and it's just LIEF that doesn't show them.

Does this match your understanding? Do you think it's worth asking LIEF about the variables?

Relatedly, on platforms where LIEF gives us both variables and functions, would it make sense also check that all expected symbols are actually exported?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, my analysis of variables is wrong. LIEF shows them. I'll revisit this later.

@real-or-random
Copy link
Contributor

real-or-random commented Nov 1, 2024

Here's a refactored version, which is more readable IMHO (haven't tested on Mac or Windows):

#!/usr/bin/env python3
"""Check that a libsecp256k1 shared library exports only expected symbols.

Usage examples:
  - When building with Autotools:
    ./tools/symbol-check.py .libs/libsecp256k1.so
    ./tools/symbol-check.py .libs/libsecp256k1-<V>.dll
    ./tools/symbol-check.py .libs/libsecp256k1.dylib

  - When building with CMake:
    ./tools/symbol-check.py build/lib/libsecp256k1.so
    ./tools/symbol-check.py build/bin/libsecp256k1-<V>.dll
    ./tools/symbol-check.py build/lib/libsecp256k1.dylib"""

import re
import sys
import subprocess

import lief


class UnexpectedExport(RuntimeError):
    pass


def get_exported_exports(library) -> list[str]:
    """Adapter function to get exported symbols based on the library format."""
    if library.format == lief.Binary.FORMATS.ELF:
        return [symbol.name for symbol in library.exported_symbols]
    elif library.format == lief.Binary.FORMATS.PE:
        return [function.name for function in library.exported_functions]
    elif library.format == lief.Binary.FORMATS.MACHO:
        return [function.name[1:] for function in library.exported_functions]
    raise NotImplementedError(f"Unsupported format: {library.format}")


def grep_expected_symbols() -> list[str]:
    """Guess the list of expected exported symbols from the source code."""
    grep_output = subprocess.check_output(
        ["git", "grep", "^SECP256K1_API", "--", "include"], # TODO WHITESPACE
        universal_newlines=True,
        encoding="utf-8"
    )
    lines = grep_output.split("\n")
    pattern = re.compile(r'\bsecp256k1_\w+')
    exported: list[str] = [pattern.findall(line)[-1] for line in lines if line.strip()]
    return exported


def check_symbols(library, expected_exports) -> None:
    """Check that the library exports only the expected symbols."""
    actual_exports = list(get_exported_exports(library))
    unexpected_exports = set(actual_exports) - set(expected_exports)
    if unexpected_exports != set():
        raise UnexpectedExport(f"Unexpected exported symbols: {unexpected_exports}")

def main():
    if len(sys.argv) != 2:
        print(__doc__)
        return 1
    library = lief.parse(sys.argv[1])
    expected_exports = grep_expected_symbols()
    try:
        check_symbols(library, expected_exports)
    except UnexpectedExport as e:
        print(f"{sys.argv[0]}: In {sys.argv[1]}: {e}")
        return 1
    return 0


if __name__ == "__main__":
    sys.exit(main())

@hebasto
Copy link
Member Author

hebasto commented Nov 1, 2024

Here's a refactored version, which is more readable IMHO (haven't tested on Mac or Windows):

Tested on macOS and on Windows. Incorporated. Thank you!

@jonasnick jonasnick mentioned this pull request Nov 4, 2024
3 tasks
@real-or-random real-or-random modified the milestones: 0.6.0, 0.6.1 Nov 4, 2024
@hebasto
Copy link
Member Author

hebasto commented Nov 4, 2024

Rebased and addressed @jonasnick's #1359 (comment).

Copy link
Contributor

@theuni theuni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code-review reACK 7ac46cf.

Still no opinion on the .py/ci.

Being able to drop -fvisibility=hidden is a nice improvement (and also a testament to the code structure!)

@hebasto hebasto force-pushed the 230626-visibility branch from 7ac46cf to a132cf5 Compare March 10, 2025 11:23
@hebasto
Copy link
Member Author

hebasto commented Mar 10, 2025

Addressed the feedback from @real-or-random and rebased.

@real-or-random
Copy link
Contributor

needs rebase, sorry :/

@hebasto hebasto force-pushed the 230626-visibility branch from a132cf5 to d147876 Compare March 11, 2025 22:00
@hebasto
Copy link
Member Author

hebasto commented Mar 11, 2025

needs rebase, sorry :/

Rebased :)

Copy link
Contributor

@real-or-random real-or-random left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reACK d147876

@real-or-random real-or-random merged commit a7a5117 into bitcoin-core:master Mar 13, 2025
117 checks passed
@hebasto hebasto deleted the 230626-visibility branch March 13, 2025 08:27
hebasto added a commit to hebasto/bitcoin that referenced this pull request Mar 17, 2025
70f149b9a1 Merge bitcoin-core/secp256k1#1662: bench: add ellswift to bench help output
6b3fe51fb6 bench: add ellswift to bench help output
d84bb83e26 Merge bitcoin-core/secp256k1#1661: configure: Show exhaustive tests in summary
3f54ed8c1b Merge bitcoin-core/secp256k1#1659: include: remove WARN_UNUSED_RESULT for functions always returning 1
20b05c9d3f configure: Show exhaustive tests in summary
e56716a3bc Merge bitcoin-core/secp256k1#1660: ci: Fix exiting from ci.sh on error
d87c3bc58f ci: Fix exiting from ci.sh on error
1b6e081538 include: remove WARN_UNUSED_RESULT for functions always returning 1
2abb35b034 Merge bitcoin-core/secp256k1#1657: tests: remove unused uncounting_illegal_callback_fn
51907fa918 tests: remove unused uncounting_illegal_callback_fn
a7a5117144 Merge bitcoin-core/secp256k1#1359: Fix symbol visibility issues, add test for it
13ed6f65dc Merge bitcoin-core/secp256k1#1593: Remove deprecated `_ec_privkey_{negate,tweak_add,tweak_mul}` aliases from API
d1478763a5 build: Drop no longer needed  `-fvisibility=hidden` compiler option
8ed1d83d92 ci: Run `tools/symbol-check.py`
41d32ab2de test: Add `tools/symbol-check.py`
88548058b3 Introduce `SECP256K1_LOCAL_VAR` macro
03bbe8c615 Merge bitcoin-core/secp256k1#1655: gha: Print all *.log files, in a separate action
59860bcc24 gha: Print all *.log files, in a separate action
4ba1ba2af9 Merge bitcoin-core/secp256k1#1647: cmake: Adjust diagnostic flags for `clang-cl`
abd25054a1 Merge bitcoin-core/secp256k1#1656: musig: Fix clearing of pubnonces
961ec25a83 musig: Fix clearing of pubnonces
3186082387 Merge bitcoin-core/secp256k1#1614: Add _ge_set_all_gej and use it in musig for own public nonces
6c2a39dafb Merge bitcoin-core/secp256k1#1639: Make static context const
37d2c60bec Remove deprecated _ec_privkey_{negate,tweak_add,tweak_mul} aliases
432ac57705 Make static context const
1b1fc09341 Merge bitcoin-core/secp256k1#1642: Verify `compressed` argument in `secp256k1_eckey_pubkey_serialize`
c0d9480fbb Merge bitcoin-core/secp256k1#1654: use `EXIT_` constants over magic numbers for indicating program execution status
13d389629a CONTRIBUTING: mention that `EXIT_` codes should be used
c855581728 test, bench, precompute_ecmult: use `EXIT_...` constants for `main` return values
965393fcea examples: use `EXIT_...` constants for `main` return values
2e3bf13653 Merge bitcoin-core/secp256k1#1646: README: add instructions for verifying GPG signatures
b682dbcf84 README: add instructions for verifying GPG signatures
00774d0723 Merge bitcoin-core/secp256k1#1650: schnorrsig: clear out masked secret key in BIP-340 nonce function
a82287fb85 schnorrsig: clear out masked secret key in BIP-340 nonce function
4c50d73dd9 ci: Add new "Windows (clang-cl)" job
84c0bd1f72 cmake: Adjust diagnostic flags for clang-cl
f79f46c703 Merge bitcoin-core/secp256k1#1641: doc: Improve cmake instructions in README
2ac9f558c4 doc: Improve cmake instructions in README
1823594761 Verify `compressed` argument in `secp256k1_eckey_pubkey_serialize`
8deef00b33 Merge bitcoin-core/secp256k1#1634: Fix some misspellings
39705450eb Fix some misspellings
ec329c2501 Merge bitcoin-core/secp256k1#1633: release cleanup: bump version after 0.6.0
c97059f594 release cleanup: bump version after 0.6.0
64228a648f musig: Use _ge_set_all_gej for own public nonces
300aab1c05 tests: Improve _ge_set_all_gej(_var) tests
365f274ce3 group: Simplify secp256k1_ge_set_all_gej
d3082ddead group: Add constant-time secp256k1_ge_set_all_gej

git-subtree-dir: src/secp256k1
git-subtree-split: 70f149b9a1bf4ed3266f97774d0ae9577534bf40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Symbol visibility
6 participants