diff --git a/slither/detectors/statements/pyth_unchecked.py b/slither/detectors/statements/pyth_unchecked.py index 959aee6a5..fa3f91b2f 100644 --- a/slither/detectors/statements/pyth_unchecked.py +++ b/slither/detectors/statements/pyth_unchecked.py @@ -24,13 +24,13 @@ def _detect(self) -> List[Output]: for contract in self.compilation_unit.contracts_derived: for target_contract, ir in contract.all_high_level_calls: if target_contract.name == "IPyth" and ir.function_name in self.PYTH_FUNCTIONS: - # We know for sure the second IR in the node is an Assignment operation of the TMP variable. Example: + # We know for sure the last IR in the node is an Assignment operation of the TMP variable. Example: # Expression: price = pyth.getEmaPriceNoOlderThan(id,age) # IRs: # TMP_0(PythStructs.Price) = HIGH_LEVEL_CALL, dest:pyth(IPyth), function:getEmaPriceNoOlderThan, arguments:['id', 'age'] # price(PythStructs.Price) := TMP_0(PythStructs.Price) - assert isinstance(ir.node.irs[1], Assignment) - return_variable = ir.node.irs[1].lvalue + assert isinstance(ir.node.irs[len(ir.node.irs) - 1], Assignment) + return_variable = ir.node.irs[len(ir.node.irs) - 1].lvalue checked = False possible_unchecked_variable_ir = None diff --git a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt index ae0dc2ae2..737b053fd 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt @@ -1,3 +1,6 @@ -Pyth price conf field is not checked in C.bad(bytes32,uint256) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#171-175) - - price = pyth.getEmaPriceNoOlderThan(id,age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#172) +Pyth price conf field is not checked in C.bad2(C.Data) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#182-186) + - price = pyth.getEmaPriceNoOlderThan(data.id,data.age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#183) + +Pyth price conf field is not checked in C.bad(bytes32,uint256) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#176-180) + - price = pyth.getEmaPriceNoOlderThan(id,age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#177) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt index cb331c8d5..fa2f9e686 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt @@ -1,3 +1,6 @@ -Pyth price publishTime field is not checked in C.bad(bytes32) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#171-175) - - price = pyth.getEmaPriceUnsafe(id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#172) +Pyth price publishTime field is not checked in C.bad(bytes32) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#175-179) + - price = pyth.getEmaPriceUnsafe(id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#176) + +Pyth price publishTime field is not checked in C.bad2(C.Data) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#181-185) + - price = pyth.getEmaPriceUnsafe(data.id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#182) diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol index 58880c382..9cdf648b2 100644 --- a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol +++ b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol @@ -164,6 +164,11 @@ interface IPyth { contract C { IPyth pyth; + struct Data { + bytes32 id; + uint256 age; + } + constructor(IPyth _pyth) { pyth = _pyth; } @@ -174,6 +179,12 @@ contract C { // Use price } + function bad2(Data calldata data) public { + PythStructs.Price memory price = pyth.getEmaPriceNoOlderThan(data.id, data.age); + require(price.publishTime > block.timestamp - 120); + // Use price + } + function good(bytes32 id, uint256 age) public { PythStructs.Price memory price = pyth.getEmaPriceNoOlderThan(id, age); require(price.conf < 10000); diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip index 6e5fa1b9f..744bc1df0 100644 Binary files a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip and b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip differ diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol index 74ab10fe3..f1c2d1398 100644 --- a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol +++ b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol @@ -164,6 +164,10 @@ interface IPyth { contract C { IPyth pyth; + struct Data { + bytes32 id; + } + constructor(IPyth _pyth) { pyth = _pyth; } @@ -174,6 +178,12 @@ contract C { // Use price } + function bad2(Data calldata data) public { + PythStructs.Price memory price = pyth.getEmaPriceUnsafe(data.id); + require(price.conf < 10000); + // Use price + } + function good(bytes32 id) public { PythStructs.Price memory price = pyth.getEmaPriceUnsafe(id); require(price.publishTime > block.timestamp - 120); diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip index 178b65b38..a3c8ece9e 100644 Binary files a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip and b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip differ