Add tools/symbol-check.py #1135

pull hebasto wants to merge 1 commits into bitcoin-core:master from hebasto:220822-symbols changing 1 files +119 −0
  1. hebasto commented at 2:57 pm on August 22, 2022: member

    The new tools/symbol-check.py aims to ensure that only expected symbols are exported in the secp256k1 shared library.

    The script itself stems from Bitcoin Core’s contrib/devtools/symbol-check.py and bitcoin/bitcoin#25020. It uses the LIEF library.

    Useful to ensure that build system changes (including bitcoin-core/secp256k1#1113) will not introduce any unexpected regressions.

  2. real-or-random commented at 5:10 pm on August 22, 2022: contributor

    I think checking that not too many symbols are exported could be interesting for us.

    Checking libraries not so much, we anyway don’t have dependencies, so all linkage should be introduced by the compiler. Or what do you think?

  3. hebasto force-pushed on Aug 23, 2022
  4. hebasto commented at 1:49 pm on August 23, 2022: member

    Checking libraries not so much, we anyway don’t have dependencies

    Cleaned up, improved, undrafted.

  5. hebasto marked this as ready for review on Aug 23, 2022
  6. hebasto renamed this:
    [WIP] Add `contrib/symbol-check.py`
    Add `contrib/symbol-check.py`
    on Aug 23, 2022
  7. real-or-random commented at 8:47 pm on August 23, 2022: contributor

    Now that I think about this, I wonder why that would be necessary. I’ve never seen any libraries doing this. I think in our case it could be helpful to prevent mistakes where we forget to make an internal function static and then it would be exported?

    But on the other hand, it’s yet another file that needs to be maintained. In particular the list of function must be kept in sync with the include files. This violates the DRY principle. Do you think the list could be generated on-the-fly, maybe just using some clever grep SECP256K1_API magic? A more elaborate version would be to use clang-query or similar, see #833, but I think this would be overkill for now.

    Weak Concept ACK because it has potential to prevent mistakes where we forget static

  8. hebasto commented at 9:16 pm on August 23, 2022: member

    I wonder why that would be necessary.

    Because quality matters :) For example:

    However, generally it is not recommended to export all the symbols in modules. Programmers can just export symbols as needed. This does not only benefit library security, but also benefits dynamic linking time.

    I’ve never seen any libraries doing this.

    https://github.com/bitcoin/bitcoin/pull/25020#issuecomment-1142151675

    I think in our case it could be helpful to prevent mistakes where we forget to make an internal function static and then it would be exported?

    The secp256k1_pre_g is not static (in most cases). Nevertheless, its export must be avoided.

    Other use cases:

    • it has helped to avoid regression in #1113
    • a sanity check of linker flags when building without any build system
    • when a build system being changed or modified
    • with future use of CMake, its new version could potentially introduce a regression into its linking code

    maybe just using some clever grep SECP256K1_API magic?

    :+1:

  9. sipa commented at 9:57 pm on November 21, 2022: contributor

    maybe just using some clever grep SECP256K1_API magic?

    That would be neat.

  10. hebasto force-pushed on Nov 30, 2022
  11. hebasto commented at 3:00 pm on November 30, 2022: member

    Updated 8ae0d514b481a2532ed86e272d6da492bee6b78a -> 766964f023a0fad52f23df742f8d5802b3890e70 (pr1135.02 -> pr1135.03, diff).

    maybe just using some clever grep SECP256K1_API magic?

    That would be neat.

    Done.

  12. real-or-random commented at 1:55 pm on December 2, 2022: contributor

    This fails for me with

    0> ./contrib/symbol-check.py ./.libs/libsecp256k1.so
    1./.libs/libsecp256k1.so: symbol memcpy from unsupported version GLIBC_2.14(4)
    2./.libs/libsecp256k1.so: failed IMPORTED_SYMBOLS
    
  13. hebasto commented at 2:17 pm on December 2, 2022: member

    This fails for me with

    What system/compiler on?

    UPD. I assume, it is a clang…

  14. sipa commented at 2:24 pm on December 2, 2022: contributor

    llibsecp256k1, unlike Bitcoin Core, has no affordances to make sure the produced builds are compatible with certain, specific, version of glibc on the user’s system.

    I think the max version checks should just be dropped here.

  15. hebasto force-pushed on Dec 2, 2022
  16. hebasto commented at 2:29 pm on December 2, 2022: member

    Updated 766964f023a0fad52f23df742f8d5802b3890e70 -> 6a97f7296342d1840b360ac18a922f6351fe06a0 (pr1135.03 -> pr1135.04, diff).

    I think the max version checks should just be dropped here.

    Done.

  17. real-or-random commented at 2:48 pm on December 2, 2022: contributor

    llibsecp256k1, unlike Bitcoin Core, has no affordances to make sure the produced builds are compatible with certain, specific, version of glibc on the user’s system.

    Ok yes, I was wondering what the purpose of the max version is… :)

  18. real-or-random commented at 3:16 pm on December 2, 2022: contributor

    Bikeshedding: I believe contrib is the wrong directory for this, see for example this attempt at a definition: https://softwareengineering.stackexchange.com/questions/252053/whats-in-the-contrib-folder#339925.

    I know, Bitcoin Core uses a different definition. My point is that the current contents of the folder fit the definition on stackexchange, so we shouldn’t mix up the two.

    I think util or tools is good a name. I wouldn’t mind putting it in the root either.

  19. hebasto force-pushed on Dec 2, 2022
  20. hebasto commented at 3:25 pm on December 2, 2022: member

    Updated 6a97f7296342d1840b360ac18a922f6351fe06a0 -> 6813bee4aacf5fee228ae8a0eaae5a5272099c03 (pr1135.04 -> pr1135.05, diff).

    I think util or tools is good a name. I wouldn’t mind putting it in the root either.

    Moved into the tools directory.

  21. fanquake commented at 3:29 pm on December 2, 2022: member

    It’s not clear to me that adding this script is worth it (especially as it continue to shrink). We seem to be adding a new language dependency, and third party library dependency, to run grep + objdump? I might have thought a bash script would be a better fit for libsecp256k1, especially since this is basically just a sanity check that will live in the CI (as the API rarely changes, and I don’t think anyone will run this locally)?

    Is there a reason this doesn’t support macOS shared libs? LIEF supports them as far as I’m aware, and it seems odd to add a platform agnostic binary parser as a dependency, and then not support all libraries that are being built.

  22. real-or-random commented at 3:39 pm on December 2, 2022: contributor

    It’s not clear to me that adding this script is worth it (especially as it continue to shrink). We seem to be adding a new language dependency, and third party library dependency, to run grep + objdump? I might have thought a bash script would be a better fit for libsecp256k1, especially since this is basically just a sanity check that will live in the CI

    I think @hebasto convinced me above that this tool has >0 benefit, but indeed, it introduces a maintenance burden and doing the same with objdump instead of Python+LIEF might reduce this burden (but I don’t know – for example I don’t know if objdump exists on macOS).

    Note that we already have python as a CI dependency for our sage scripts.

  23. real-or-random renamed this:
    Add `contrib/symbol-check.py`
    Add `tools/symbol-check.py`
    on Dec 2, 2022
  24. fanquake commented at 3:52 pm on December 2, 2022: member

    (but I don’t know – for example I don’t know if objdump exists on macOS).

    It does, but at the moment, I guess that doesn’t matter, given the script doesn’t check macOS libs.

    Would you expect an API issue to be present in one shared library, but not all others? We might be able to get away with just sanity checking an ELF lib, as I assume if there’s an issue that you’d want to catch, present there, it’ll be present everywhere.

  25. hebasto force-pushed on Dec 4, 2022
  26. hebasto commented at 9:44 am on December 4, 2022: member

    Is there a reason this doesn’t support macOS shared libs?

    Updated to support macOS libs. LIEF v0.13.0 (not released yet) is required.

    Also: https://lief-project.github.io/blog/2022-05-08-macho/

  27. fanquake commented at 3:08 pm on December 4, 2022: member

    LIEF v0.13.0 (not released yet) is required.

    Looks like you could do something like this to check that the expected exports are present? Works with LIEF 0.12.3 (latest release):

     0diff --git a/tools/symbol-check.py b/tools/symbol-check.py
     1index 8206b95..7237158 100755
     2--- a/tools/symbol-check.py
     3+++ b/tools/symbol-check.py
     4@@ -59,12 +59,10 @@ def check_MACHO_exported_functions(library, expected_exports) -> bool:
     5     ok: bool = True
     6     macho_lib: lief.MACHO.Binary = library.concrete
     7 
     8-    for function in macho_lib.exported_functions:
     9-        name: str = function.name[1:]
    10-        if name in expected_exports:
    11-            continue
    12-        print(f'{filename}: export of function {name} not expected')
    13-        ok = False
    14+    for name in expected_exports:
    15+        if not macho_lib.has_symbol(name):
    16+            print(f'{filename}: export of function {name} missing')
    17+            ok = False
    
  28. in tools/symbol-check.py:30 in 6e6aa4915e outdated
    25+    grep_output = subprocess.check_output(["git", "grep", "^SECP256K1_API", "--", "include"], universal_newlines=True, encoding="utf8")
    26+    lines = grep_output.split("\n")
    27+    exports: List[str] = []
    28+    for line in lines:
    29+        if line.strip():
    30+            function_name = re.sub(r'\W', '', line.split(" ")[-1])
    


    real-or-random commented at 9:54 pm on December 12, 2022:
    this doesn’t work with include/secp256k1.h:SECP256K1_API void secp256k1_selftest(void); for which the script assumes the symbol is secp256k1_selftestvoid

    hebasto commented at 3:32 pm on December 13, 2022:
    Thanks! Fixed.
  29. real-or-random cross-referenced this on Dec 12, 2022 from issue release: Refine process by real-or-random
  30. hebasto force-pushed on Dec 13, 2022
  31. hebasto commented at 3:32 pm on December 13, 2022: member

    Updated 6e6aa4915eb5e984928bbb8b675cf55fd5e67879 -> cc7933d47d70e93ef578b01f7a3336cf0aeaaaa7 (pr1135.06 -> pr1135.07):

  32. Add `tools/symbol-check.py` 71ceda779d
  33. hebasto force-pushed on Dec 15, 2022
  34. real-or-random cross-referenced this on Dec 19, 2022 from issue Symbol visibility by real-or-random
  35. real-or-random commented at 4:23 pm on December 19, 2022: contributor

    We’ve discussed this at length in the meeting today, see https://gnusha.org/secp256k1/2022-12-19.log for details.

    Conclusion:

    • @hebasto will try to incorporate the suggestion from @fanquake to make this work on current LIEF functions
    • @hebasto will add commits that call the script in CI, and maybe add builds with -fvisibility=default
  36. hebasto commented at 12:22 pm on December 20, 2022: member
    • @hebasto will try to incorporate the suggestion from @fanquake to make this work on current LIEF functions

    LIEF v0.13.0 (not released yet) is required.

    Looks like you could do something like this to check that the expected exports are present? Works with LIEF 0.12.3 (latest release):

     0diff --git a/tools/symbol-check.py b/tools/symbol-check.py
     1index 8206b95..7237158 100755
     2--- a/tools/symbol-check.py
     3+++ b/tools/symbol-check.py
     4@@ -59,12 +59,10 @@ def check_MACHO_exported_functions(library, expected_exports) -> bool:
     5     ok: bool = True
     6     macho_lib: lief.MACHO.Binary = library.concrete
     7 
     8-    for function in macho_lib.exported_functions:
     9-        name: str = function.name[1:]
    10-        if name in expected_exports:
    11-            continue
    12-        print(f'{filename}: export of function {name} not expected')
    13-        ok = False
    14+    for name in expected_exports:
    15+        if not macho_lib.has_symbol(name):
    16+            print(f'{filename}: export of function {name} missing')
    17+            ok = False
    

    As the suggested approach changes the check logic, the script fails if any of modules are disabled. For example, the “recovery” module is disabled by default, and script ends with:

    0.libs/libsecp256k1.1.dylib: export of function secp256k1_ecdsa_recoverable_signature_parse_compact missing
    1.libs/libsecp256k1.1.dylib: export of function secp256k1_ecdsa_recoverable_signature_convert missing
    2.libs/libsecp256k1.1.dylib: export of function secp256k1_ecdsa_recoverable_signature_serialize_compact missing
    3.libs/libsecp256k1.1.dylib: export of function secp256k1_ecdsa_sign_recoverable missing
    4.libs/libsecp256k1.1.dylib: export of function secp256k1_ecdsa_recover missing
    5.libs/libsecp256k1.1.dylib: failed EXPORTED_FUNCTIONS
    

    Making this PR a draft for now.

  37. hebasto marked this as a draft on Dec 20, 2022
  38. sipa cross-referenced this on Jan 9, 2023 from issue Make all non-API functions (except main) static by sipa
  39. hebasto closed this on Feb 23, 2023

  40. hebasto cross-referenced this on May 5, 2023 from issue abi: Use dllexport for mingw builds by theuni
  41. hebasto cross-referenced this on Jun 26, 2023 from issue Fix symbol visibility issues, add test for it by hebasto
  42. hebasto deleted the branch on Jun 26, 2023

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/secp256k1. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-11-23 10:15 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me