Skip to content

Commit

Permalink
Merge pull request #477 from crytic/fix/compile-libraries-validation
Browse files Browse the repository at this point in the history
Allow 20 byte address for --compile-libraries and raise error if argument is invalid
  • Loading branch information
0xalpharush authored Aug 8, 2023
2 parents 9ec6702 + 9a0cb86 commit ef7173b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 4 deletions.
9 changes: 5 additions & 4 deletions crytic_compile/crytic_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,14 @@ def _extract_libraries(libraries_str: Optional[str]) -> Optional[Dict[str, int]]

if not libraries_str:
return None

pattern = r"\((?P<name>\w+),\s*(?P<value1>0x[0-9a-fA-F]{2})\),?"
# Extract tuple like (libname1, 0x00)
pattern = r"\((?P<name>\w+),\s*(?P<value1>0x[0-9a-fA-F]{2,40})\),?"
matches = re.findall(pattern, libraries_str)

if not matches:
logging.info(f"Libraries {libraries_str} could not be parsed")
return None
raise ValueError(
f"Invalid library linking directive\nGot:\n{libraries_str}\nExpected format:\n(libname1, 0x00),(libname2, 0x02)"
)

ret: Dict[str, int] = {}
for key, value in matches:
Expand Down
16 changes: 16 additions & 0 deletions tests/library_linking.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
library NeedsLinkingA {
function testA() external pure returns (uint) {
return type(uint).max;
}
}
library NeedsLinkingB {
function testB() external pure returns (uint) {
return type(uint).min;
}
}
contract TestLibraryLinking {
function test() external {
NeedsLinkingA.testA();
NeedsLinkingB.testB();
}
}
54 changes: 54 additions & 0 deletions tests/test_library_linking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""
Test library linking
"""
import re
from pathlib import Path
import pytest
from crytic_compile.crytic_compile import CryticCompile

TEST_DIR = Path(__file__).resolve().parent

LIBRARY_PLACEHOLDER_REGEX = r"__.{36}__"


def test_library_linking() -> None:
"""Test that the placeholder is not present in the bytecode when the libraries are provided"""
cc = CryticCompile(
Path(TEST_DIR / "library_linking.sol").as_posix(),
compile_libraries="(NeedsLinkingA, 0xdead),(NeedsLinkingB, 0x000000000000000000000000000000000000beef)",
)
for compilation_unit in cc.compilation_units.values():
for source_unit in compilation_unit.source_units.values():
assert (
len(re.findall(r"__.{36}__", source_unit.bytecode_init("TestLibraryLinking"))) == 2
)
assert (
len(re.findall(r"__.{36}__", source_unit.bytecode_runtime("TestLibraryLinking")))
== 2
)
libraries = compilation_unit.crytic_compile.libraries
assert (
len(
re.findall(
r"__.{36}__", source_unit.bytecode_init("TestLibraryLinking", libraries)
)
)
== 0
)
assert (
len(
re.findall(
r"__.{36}__", source_unit.bytecode_runtime("TestLibraryLinking", libraries)
)
)
== 0
)


def test_library_linking_validation() -> None:
"""Test that invalid compile libraries argument raises an error"""
with pytest.raises(ValueError):
CryticCompile(
Path(TEST_DIR / "library_linking.sol").as_posix(),
compile_libraries="(NeedsLinkingA, 0x)",
)

0 comments on commit ef7173b

Please sign in to comment.