mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Manual merge
This commit is contained in:
commit
6ede17e440
10
Changelog.md
10
Changelog.md
@ -1,6 +1,11 @@
|
||||
### 0.8.4 (unreleased)
|
||||
|
||||
Important Bugfixes:
|
||||
* ABI Decoder V2: For two-dimensional arrays and specially crafted data in memory, the result of ``abi.decode`` can depend on data elsewhere in memory. Calldata decoding is not affected.
|
||||
|
||||
|
||||
Language Features:
|
||||
* Assembly / Yul: Allow hex string literals.
|
||||
* Possibility to use ``bytes.concat`` with variable number of ``bytes`` and ``bytesNN`` arguments which behaves as a restricted version of `abi.encodePacked` with a more descriptive name.
|
||||
* Support custom errors via the ``error`` keyword and introduce the ``revert`` statement.
|
||||
|
||||
@ -9,19 +14,24 @@ Compiler Features:
|
||||
* Analysis: Properly detect circular references to the bytecode of other contracts across all function calls.
|
||||
* Commandline Interface: Model checker option ``--model-checker-targets`` also accepts ``outOfBounds``.
|
||||
* Low-Level Inliner: Inline ordinary jumps to small blocks and jumps to small blocks that terminate.
|
||||
* SMTChecker: Deprecate ``pragma experimental SMTChecker;`` and set default model checker engine to ``none``.
|
||||
* SMTChecker: Report local variables in CHC counterexamples.
|
||||
* SMTChecker: Report out of bounds index access for arrays and fixed bytes.
|
||||
* Standard JSON: Model checker option ``settings.modelChecker.targets`` also accepts ``outOfBounds``.
|
||||
* Yul Optimizer: Added a new step FunctionSpecializer, that specializes a function with its literal arguments.
|
||||
* Yul EVM Code Transform: Stack Optimization: Reuse slots of unused function arguments and defer allocating stack slots for return variables until after expression statements and assignments that do not reference them.
|
||||
* NatSpec: Allow ``@notice`` tag on non-public state variables and local variable declarations. The documentation will only be part of the AST, under the field ``documentation``.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* Antlr Grammar: Fix parsing of import paths involving properly distinguishing between empty and non-empty string literals in general.
|
||||
* AST Output: Fix ``kind`` field of ``ModifierInvocation`` for base constructor calls.
|
||||
* SMTChecker: Fix false positive and false negative on ``push`` as LHS of a compound assignment.
|
||||
* SMTChecker: Fix false positive in contracts that cannot be deployed.
|
||||
* SMTChecker: Fix internal error on public getter returning dynamic data on older EVM versions where these are not available.
|
||||
* SMTChecker: Fix internal error on try-catch with function call in catch block.
|
||||
* Type Checker: Fix missing error when events are used without an emit statement.
|
||||
* Commandline interface: Fix internal error when printing AST and using ``--base-path`` or ``file://`` prefix in imports.
|
||||
|
||||
|
||||
AST Changes:
|
||||
|
@ -55,8 +55,9 @@
|
||||
- [ ] Wait for the ``~ethereum/ubuntu/ethereum-static`` PPA build to be finished and published for *all platforms*. SERIOUSLY: DO NOT PROCEED EARLIER!!! *After* the static builds are *published*, copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty``, ``Xenial`` and ``Bionic`` while selecting ``Copy existing binaries``.
|
||||
|
||||
### Documentation
|
||||
- [ ] Build the new version on https://readthedocs.org/projects/solidity/ (select `latest` at the bottom of the page and click `BUILD`)
|
||||
- [ ] Build the new version on https://readthedocs.org/projects/solidity/ (select `latest` at the bottom of the page and click `BUILD`).
|
||||
- [ ] In the admin panel, select `Versions` in the menu and set the default version to the released one.
|
||||
- [ ] If it is a non-breaking release, block indexing of previous release version in the ``robots.txt`` file.
|
||||
|
||||
### Release solc-js
|
||||
- [ ] Wait until solc-bin was properly deployed. You can test this via remix - a test run through remix is advisable anyway.
|
||||
|
@ -146,6 +146,8 @@ This section lists changes that might cause existing contracts to not compile an
|
||||
|
||||
* The ``chainid`` builtin in inline assembly is now considered ``view`` instead of ``pure``.
|
||||
|
||||
* Unary negation cannot be used on unsigned integers anymore, only on signed integers.
|
||||
|
||||
Interface Changes
|
||||
=================
|
||||
|
||||
@ -170,4 +172,5 @@ How to update your code
|
||||
- Combine ``c.f{gas: 10000}{value: 1}()`` to ``c.f{gas: 10000, value: 1}()``.
|
||||
- Change ``msg.sender.transfer(x)`` to ``payable(msg.sender).transfer(x)`` or use a stored variable of ``address payable`` type.
|
||||
- Change ``x**y**z`` to ``(x**y)**z``.
|
||||
- Use inline assembly as a replacement for ``log0``, ..., ``log4``.
|
||||
- Use inline assembly as a replacement for ``log0``, ..., ``log4``.
|
||||
- Negate unsigned integers by subtracting them from the maximum value of the type and adding 1 (e.g. ``type(uint256).max - x + 1``, while ensuring that `x` is not zero)
|
||||
|
95
docs/_static/robots.txt
vendored
Normal file
95
docs/_static/robots.txt
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
Sitemap: http://docs.soliditylang.org/sitemap.xml
|
||||
|
||||
# Prevent documentation for the development branches from showing up in search results.
|
||||
Disallow: /en/develop/
|
||||
Disallow: /en/breaking/
|
||||
|
||||
# Prevent documentation for the older Solidity versions from showing up in search results.
|
||||
|
||||
Disallow: /en/v0.1.2/
|
||||
Disallow: /en/v0.1.3/
|
||||
Disallow: /en/v0.1.4/
|
||||
Disallow: /en/v0.1.5/
|
||||
Disallow: /en/v0.1.6/
|
||||
Disallow: /en/v0.1.7/
|
||||
Disallow: /en/v0.2.0/
|
||||
Disallow: /en/v0.2.1/
|
||||
Disallow: /en/v0.2.2/
|
||||
Disallow: /en/v0.3.0/
|
||||
Disallow: /en/v0.3.1/
|
||||
Disallow: /en/v0.3.2/
|
||||
Disallow: /en/v0.3.3/
|
||||
Disallow: /en/v0.3.4/
|
||||
Disallow: /en/v0.3.5/
|
||||
Disallow: /en/v0.3.6/
|
||||
Disallow: /en/v0.4.0/
|
||||
Disallow: /en/v0.4.1/
|
||||
Disallow: /en/v0.4.2/
|
||||
Disallow: /en/v0.4.3/
|
||||
Disallow: /en/v0.4.4/
|
||||
Disallow: /en/v0.4.5/
|
||||
Disallow: /en/v0.4.6/
|
||||
Disallow: /en/v0.4.7/
|
||||
Disallow: /en/v0.4.8/
|
||||
Disallow: /en/v0.4.9/
|
||||
Disallow: /en/v0.4.10/
|
||||
Disallow: /en/v0.4.11/
|
||||
Disallow: /en/v0.4.12/
|
||||
Disallow: /en/v0.4.13/
|
||||
Disallow: /en/v0.4.14/
|
||||
Disallow: /en/v0.4.15/
|
||||
Disallow: /en/v0.4.16/
|
||||
Disallow: /en/v0.4.17/
|
||||
Disallow: /en/v0.4.18/
|
||||
Disallow: /en/v0.4.19/
|
||||
Disallow: /en/v0.4.20/
|
||||
Disallow: /en/v0.4.21/
|
||||
Disallow: /en/v0.4.22/
|
||||
Disallow: /en/v0.4.23/
|
||||
Disallow: /en/v0.4.24/
|
||||
Disallow: /en/v0.4.25/
|
||||
Disallow: /en/v0.4.26/
|
||||
Disallow: /en/v0.5.0/
|
||||
Disallow: /en/v0.5.1/
|
||||
Disallow: /en/v0.5.2/
|
||||
Disallow: /en/v0.5.3/
|
||||
Disallow: /en/v0.5.4/
|
||||
Disallow: /en/v0.5.5/
|
||||
Disallow: /en/v0.5.6/
|
||||
Disallow: /en/v0.5.7/
|
||||
Disallow: /en/v0.5.8/
|
||||
Disallow: /en/v0.5.9/
|
||||
Disallow: /en/v0.5.10/
|
||||
Disallow: /en/v0.5.11/
|
||||
Disallow: /en/v0.5.12/
|
||||
Disallow: /en/v0.5.13/
|
||||
Disallow: /en/v0.5.14/
|
||||
Disallow: /en/v0.5.15/
|
||||
Disallow: /en/v0.5.16/
|
||||
Disallow: /en/v0.5.17/
|
||||
Disallow: /en/v0.6.0/
|
||||
Disallow: /en/v0.6.1/
|
||||
Disallow: /en/v0.6.2/
|
||||
Disallow: /en/v0.6.3/
|
||||
Disallow: /en/v0.6.4/
|
||||
Disallow: /en/v0.6.5/
|
||||
Disallow: /en/v0.6.6/
|
||||
Disallow: /en/v0.6.7/
|
||||
Disallow: /en/v0.6.8/
|
||||
Disallow: /en/v0.6.9/
|
||||
Disallow: /en/v0.6.10/
|
||||
Disallow: /en/v0.6.11/
|
||||
Disallow: /en/v0.6.12/
|
||||
Disallow: /en/v0.7.0/
|
||||
Disallow: /en/v0.7.1/
|
||||
Disallow: /en/v0.7.2/
|
||||
Disallow: /en/v0.7.3/
|
||||
Disallow: /en/v0.7.4/
|
||||
Disallow: /en/v0.7.5/
|
||||
# Allow the last patch release of the 0.7.x series
|
||||
#Disallow: /en/v0.7.6/
|
||||
Disallow: /en/v0.8.0/
|
||||
Disallow: /en/v0.8.1/
|
||||
Disallow: /en/v0.8.2/
|
||||
# Allow the latest release
|
||||
#Disallow: /en/v0.8.3/
|
@ -1,4 +1,15 @@
|
||||
[
|
||||
{
|
||||
"name": "ABIDecodeTwoDimensionalArrayMemory",
|
||||
"summary": "If used on memory byte arrays, result of the function ``abi.decode`` can depend on the contents of memory outside of the actual byte array that is decoded.",
|
||||
"description": "The ABI specification uses pointers to data areas for everything that is dynamically-sized. When decoding data from memory (instead of calldata), the ABI decoder did not properly validate some of these pointers. More specifically, it was possible to use large values for the pointers inside arrays such that computing the offset resulted in an undetected overflow. This could lead to these pointers targeting areas in memory outside of the actual area to be decoded. This way, it was possible for ``abi.decode`` to return different values for the same encoded byte array.",
|
||||
"introduced": "0.4.16",
|
||||
"fixed": "0.8.4",
|
||||
"conditions": {
|
||||
"ABIEncoderV2": true
|
||||
},
|
||||
"severity": "very low"
|
||||
},
|
||||
{
|
||||
"name": "KeccakCaching",
|
||||
"summary": "The bytecode optimizer incorrectly re-used previously evaluated Keccak-256 hashes. You are unlikely to be affected if you do not compute Keccak-256 hashes in inline assembly.",
|
||||
|
@ -595,6 +595,7 @@
|
||||
},
|
||||
"0.4.16": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -615,6 +616,7 @@
|
||||
},
|
||||
"0.4.17": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -636,6 +638,7 @@
|
||||
},
|
||||
"0.4.18": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -656,6 +659,7 @@
|
||||
},
|
||||
"0.4.19": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -699,6 +703,7 @@
|
||||
},
|
||||
"0.4.20": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -720,6 +725,7 @@
|
||||
},
|
||||
"0.4.21": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -741,6 +747,7 @@
|
||||
},
|
||||
"0.4.22": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -762,6 +769,7 @@
|
||||
},
|
||||
"0.4.23": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -782,6 +790,7 @@
|
||||
},
|
||||
"0.4.24": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -802,6 +811,7 @@
|
||||
},
|
||||
"0.4.25": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -820,6 +830,7 @@
|
||||
},
|
||||
"0.4.26": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -987,6 +998,7 @@
|
||||
},
|
||||
"0.5.0": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1005,6 +1017,7 @@
|
||||
},
|
||||
"0.5.1": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1023,6 +1036,7 @@
|
||||
},
|
||||
"0.5.10": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1037,6 +1051,7 @@
|
||||
},
|
||||
"0.5.11": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1050,6 +1065,7 @@
|
||||
},
|
||||
"0.5.12": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1063,6 +1079,7 @@
|
||||
},
|
||||
"0.5.13": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1076,6 +1093,7 @@
|
||||
},
|
||||
"0.5.14": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1091,6 +1109,7 @@
|
||||
},
|
||||
"0.5.15": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1105,6 +1124,7 @@
|
||||
},
|
||||
"0.5.16": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1118,6 +1138,7 @@
|
||||
},
|
||||
"0.5.17": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1130,6 +1151,7 @@
|
||||
},
|
||||
"0.5.2": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1148,6 +1170,7 @@
|
||||
},
|
||||
"0.5.3": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1166,6 +1189,7 @@
|
||||
},
|
||||
"0.5.4": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1184,6 +1208,7 @@
|
||||
},
|
||||
"0.5.5": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1204,6 +1229,7 @@
|
||||
},
|
||||
"0.5.6": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1224,6 +1250,7 @@
|
||||
},
|
||||
"0.5.7": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1242,6 +1269,7 @@
|
||||
},
|
||||
"0.5.8": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1259,6 +1287,7 @@
|
||||
},
|
||||
"0.5.9": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1275,6 +1304,7 @@
|
||||
},
|
||||
"0.6.0": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1289,6 +1319,7 @@
|
||||
},
|
||||
"0.6.1": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1302,6 +1333,7 @@
|
||||
},
|
||||
"0.6.10": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup"
|
||||
@ -1310,6 +1342,7 @@
|
||||
},
|
||||
"0.6.11": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup"
|
||||
@ -1318,6 +1351,7 @@
|
||||
},
|
||||
"0.6.12": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup"
|
||||
@ -1326,6 +1360,7 @@
|
||||
},
|
||||
"0.6.2": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1339,6 +1374,7 @@
|
||||
},
|
||||
"0.6.3": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1352,6 +1388,7 @@
|
||||
},
|
||||
"0.6.4": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1365,6 +1402,7 @@
|
||||
},
|
||||
"0.6.5": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1377,6 +1415,7 @@
|
||||
},
|
||||
"0.6.6": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1388,6 +1427,7 @@
|
||||
},
|
||||
"0.6.7": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1399,6 +1439,7 @@
|
||||
},
|
||||
"0.6.8": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup"
|
||||
@ -1407,6 +1448,7 @@
|
||||
},
|
||||
"0.6.9": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1416,6 +1458,7 @@
|
||||
},
|
||||
"0.7.0": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup"
|
||||
@ -1424,6 +1467,7 @@
|
||||
},
|
||||
"0.7.1": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup",
|
||||
@ -1433,6 +1477,7 @@
|
||||
},
|
||||
"0.7.2": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy",
|
||||
"DynamicArrayCleanup"
|
||||
@ -1441,6 +1486,7 @@
|
||||
},
|
||||
"0.7.3": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching",
|
||||
"EmptyByteArrayCopy"
|
||||
],
|
||||
@ -1448,42 +1494,50 @@
|
||||
},
|
||||
"0.7.4": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching"
|
||||
],
|
||||
"released": "2020-10-19"
|
||||
},
|
||||
"0.7.5": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching"
|
||||
],
|
||||
"released": "2020-11-18"
|
||||
},
|
||||
"0.7.6": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching"
|
||||
],
|
||||
"released": "2020-12-16"
|
||||
},
|
||||
"0.8.0": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching"
|
||||
],
|
||||
"released": "2020-12-16"
|
||||
},
|
||||
"0.8.1": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching"
|
||||
],
|
||||
"released": "2021-01-27"
|
||||
},
|
||||
"0.8.2": {
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory",
|
||||
"KeccakCaching"
|
||||
],
|
||||
"released": "2021-03-02"
|
||||
},
|
||||
"0.8.3": {
|
||||
"bugs": [],
|
||||
"bugs": [
|
||||
"ABIDecodeTwoDimensionalArrayMemory"
|
||||
],
|
||||
"released": "2021-03-23"
|
||||
}
|
||||
}
|
@ -156,7 +156,7 @@ html_js_files = ["js/toggle.js"]
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
html_extra_path = ["_static/css"]
|
||||
html_extra_path = ["_static/css", "_static/robots.txt"]
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
|
@ -33,7 +33,7 @@ the team and contributors are working on, you can join our public team calls:
|
||||
- Mondays at 3pm CET/CEST.
|
||||
- Wednesdays at 2pm CET/CEST.
|
||||
|
||||
Both calls take place on `Google Meet <https://meet.google.com/mrq-kbwv-edg>`_.
|
||||
Both calls take place on `Jitsi <https://meet.komputing.org/solidity>`_.
|
||||
|
||||
How to Report Issues
|
||||
====================
|
||||
|
@ -478,6 +478,7 @@ In any case, you will get a warning about the outer variable being shadowed.
|
||||
}
|
||||
|
||||
|
||||
.. index:: ! safe math, safemath, checked, unchecked
|
||||
.. _unchecked:
|
||||
|
||||
Checked or Unchecked Arithmetic
|
||||
@ -501,11 +502,11 @@ To obtain the previous behaviour, an ``unchecked`` block can be used:
|
||||
pragma solidity ^0.8.0;
|
||||
contract C {
|
||||
function f(uint a, uint b) pure public returns (uint) {
|
||||
// This addition will wrap on underflow.
|
||||
// This subtraction will wrap on underflow.
|
||||
unchecked { return a - b; }
|
||||
}
|
||||
function g(uint a, uint b) pure public returns (uint) {
|
||||
// This addition will revert on underflow.
|
||||
// This subtraction will revert on underflow.
|
||||
return a - b;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ Creating and verifying signatures
|
||||
=================================
|
||||
|
||||
Imagine Alice wants to send a quantity of Ether to Bob, i.e.
|
||||
Alice is the sender and the Bob is the recipient.
|
||||
Alice is the sender and Bob is the recipient.
|
||||
|
||||
Alice only needs to send cryptographically signed messages off-chain
|
||||
(e.g. via email) to Bob and it is similar to writing checks.
|
||||
|
@ -2,12 +2,12 @@
|
||||
Language Grammar
|
||||
****************
|
||||
|
||||
.. a4:autogrammar:: Solidity
|
||||
:only-reachable-from: Solidity.sourceUnit
|
||||
.. a4:autogrammar:: SolidityParser
|
||||
:only-reachable-from: SolidityParser.sourceUnit
|
||||
:undocumented:
|
||||
:cc-to-dash:
|
||||
|
||||
.. a4:autogrammar:: SolidityLexer
|
||||
:only-reachable-from: Solidity.sourceUnit
|
||||
:only-reachable-from: SolidityParser.sourceUnit
|
||||
:fragments:
|
||||
:cc-to-dash:
|
@ -155,15 +155,20 @@ Not: '!';
|
||||
BitNot: '~';
|
||||
Inc: '++';
|
||||
Dec: '--';
|
||||
//@doc:inline
|
||||
DoubleQuote: '"';
|
||||
//@doc:inline
|
||||
SingleQuote: '\'';
|
||||
|
||||
/**
|
||||
* A single quoted string literal restricted to printable characters.
|
||||
*/
|
||||
StringLiteral: '"' DoubleQuotedStringCharacter* '"' | '\'' SingleQuotedStringCharacter* '\'';
|
||||
/**
|
||||
* A single non-empty quoted string literal.
|
||||
* A non-empty quoted string literal restricted to printable characters.
|
||||
*/
|
||||
NonEmptyStringLiteral: '"' DoubleQuotedStringCharacter+ '"' | '\'' SingleQuotedStringCharacter+ '\'';
|
||||
/**
|
||||
* An empty string literal
|
||||
*/
|
||||
EmptyStringLiteral: '"' '"' | '\'' '\'';
|
||||
|
||||
// Note that this will also be used for Yul string literals.
|
||||
//@doc:inline
|
||||
fragment DoubleQuotedStringCharacter: DoubleQuotedPrintable | EscapeSequence;
|
||||
@ -200,6 +205,7 @@ fragment DoubleQuotedUnicodeStringCharacter: ~["\r\n\\] | EscapeSequence;
|
||||
//@doc:inline
|
||||
fragment SingleQuotedUnicodeStringCharacter: ~['\r\n\\] | EscapeSequence;
|
||||
|
||||
// Note that this will also be used for Yul hex string literals.
|
||||
/**
|
||||
* Hex strings need to consist of an even number of hex digits that may be grouped using underscores.
|
||||
*/
|
||||
@ -263,6 +269,7 @@ YulLeave: 'leave';
|
||||
YulLet: 'let';
|
||||
YulSwitch: 'switch';
|
||||
YulTrue: 'true';
|
||||
YulHex: 'hex';
|
||||
|
||||
/**
|
||||
* Builtin functions in the EVM Yul dialect.
|
||||
@ -314,7 +321,8 @@ YulDecimalNumber: '0' | ([1-9] [0-9]*);
|
||||
YulStringLiteral:
|
||||
'"' DoubleQuotedStringCharacter* '"'
|
||||
| '\'' SingleQuotedStringCharacter* '\'';
|
||||
|
||||
//@doc:inline
|
||||
YulHexStringLiteral: HexString;
|
||||
|
||||
YulWS: [ \t\r\n\u000C]+ -> skip ;
|
||||
YulCOMMENT: '/*' .*? '*/' -> channel(HIDDEN) ;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Solidity is a statically typed, contract-oriented, high-level language for implementing smart contracts on the Ethereum platform.
|
||||
*/
|
||||
grammar Solidity;
|
||||
parser grammar SolidityParser;
|
||||
|
||||
options { tokenVocab=SolidityLexer; }
|
||||
|
||||
@ -388,7 +388,7 @@ booleanLiteral: True | False;
|
||||
/**
|
||||
* A full string literal consists of either one or several consecutive quoted strings.
|
||||
*/
|
||||
stringLiteral: StringLiteral+;
|
||||
stringLiteral: (NonEmptyStringLiteral | EmptyStringLiteral)+;
|
||||
/**
|
||||
* A full hex string literal that consists of either one or several consecutive hex strings.
|
||||
*/
|
||||
@ -564,5 +564,5 @@ yulPath: YulIdentifier (YulPeriod YulIdentifier)*;
|
||||
*/
|
||||
yulFunctionCall: (YulIdentifier | YulEVMBuiltin) YulLParen (yulExpression (YulComma yulExpression)*)? YulRParen;
|
||||
yulBoolean: YulTrue | YulFalse;
|
||||
yulLiteral: YulDecimalNumber | YulStringLiteral | YulHexNumber | yulBoolean;
|
||||
yulLiteral: YulDecimalNumber | YulStringLiteral | YulHexNumber | yulBoolean | YulHexStringLiteral;
|
||||
yulExpression: yulPath | yulFunctionCall | yulLiteral;
|
@ -39,8 +39,17 @@ The potential warnings that the SMTChecker reports are:
|
||||
- ``<failing property> happens here.``. This means that the SMTChecker proved that a certain property fails. A counterexample may be given, however in complex situations it may also not show a counterexample. This result may also be a false positive in certain cases, when the SMT encoding adds abstractions for Solidity code that is either hard or impossible to express.
|
||||
- ``<failing property> might happen here``. This means that the solver could not prove either case within the given timeout. Since the result is unknown, the SMTChecker reports the potential failure for soundness. This may be solved by increasing the query timeout, but the problem might also simply be too hard for the engine to solve.
|
||||
|
||||
It is currently an experimental feature, therefore in order to use it you need
|
||||
to enable it via :ref:`a pragma directive<smt_checker>`.
|
||||
To enable the SMTChecker, you must select :ref:`which engine should run<smtchecker_engines>`,
|
||||
where the default is no engine. Selecting the engine enables the SMTChecker on all files.
|
||||
|
||||
.. note::
|
||||
|
||||
Prior to Solidity 0.8.4, the default way to enable the SMTChecker was via
|
||||
``pragma experimental SMTChecker;`` and only the contracts containing the
|
||||
pragma would be analyzed. That pragma has been deprecated, and although it
|
||||
still enables the SMTChecker for backwards compatibility, it will be removed
|
||||
in Solidity 0.9.0. Note also that now using the pragma even in a single file
|
||||
enables the SMTChecker for all files.
|
||||
|
||||
.. note::
|
||||
The lack of warnings for a verification target represents an undisputed
|
||||
@ -62,9 +71,8 @@ Overflow
|
||||
|
||||
.. code-block:: Solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
contract Overflow {
|
||||
uint immutable x;
|
||||
@ -110,9 +118,8 @@ the SMTChecker proves that no overflow is reachable (by not reporting warnings):
|
||||
|
||||
.. code-block:: Solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
contract Overflow {
|
||||
uint immutable x;
|
||||
@ -149,9 +156,8 @@ definition to see what results come out!
|
||||
|
||||
.. code-block:: Solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
contract Monotonic {
|
||||
function f(uint _x) internal pure returns (uint) {
|
||||
@ -172,9 +178,8 @@ equal every element in the array.
|
||||
|
||||
.. code-block:: Solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
contract Max {
|
||||
function max(uint[] memory _a) public pure returns (uint) {
|
||||
@ -206,9 +211,8 @@ For example, changing the code to
|
||||
|
||||
.. code-block:: Solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
contract Max {
|
||||
function max(uint[] memory _a) public pure returns (uint) {
|
||||
@ -259,10 +263,8 @@ below.
|
||||
|
||||
.. code-block:: Solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
|
||||
contract Robot {
|
||||
int x = 0;
|
||||
@ -361,9 +363,8 @@ anything, including reenter the caller contract.
|
||||
|
||||
.. code-block:: Solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
interface Unknown {
|
||||
function run() external;
|
||||
@ -469,6 +470,8 @@ A common subset of targets might be, for example:
|
||||
There is no precise heuristic on how and when to split verification targets,
|
||||
but it can be useful especially when dealing with large contracts.
|
||||
|
||||
.. _smtchecker_engines:
|
||||
|
||||
Model Checking Engines
|
||||
======================
|
||||
|
||||
@ -624,8 +627,6 @@ not mean loss of proving power.
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This may report a warning if no SMT solver is available.
|
||||
|
||||
contract Recover
|
||||
{
|
||||
@ -673,8 +674,6 @@ types.
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.0;
|
||||
pragma experimental SMTChecker;
|
||||
// This will report a warning
|
||||
|
||||
contract Aliasing
|
||||
{
|
||||
|
@ -136,8 +136,8 @@ a reference to it.
|
||||
|
||||
.. _bytes:
|
||||
|
||||
``bytes`` and ``strings`` as Arrays
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
``bytes`` and ``string`` as Arrays
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Variables of type ``bytes`` and ``string`` are special arrays. A ``bytes`` is similar to ``byte[]``,
|
||||
but it is packed tightly in calldata and memory. ``string`` is equal to ``bytes`` but does not allow
|
||||
|
@ -174,7 +174,10 @@ whitespace, i.e. there is no terminating ``;`` or newline required.
|
||||
Literals
|
||||
--------
|
||||
|
||||
You can use integer constants in decimal or hexadecimal notation.
|
||||
As literals, you can use integer constants in decimal or hexadecimal notation
|
||||
or strings as ASCII (`"abc"`) or HEX strings (`hex"616263"`) of up to
|
||||
32 bytes length.
|
||||
|
||||
When compiling for the EVM, this will be translated into an
|
||||
appropriate ``PUSHi`` instruction. In the following example,
|
||||
``3`` and ``2`` are added resulting in 5 and then the
|
||||
|
@ -82,7 +82,12 @@ bool Inliner::isInlineCandidate(size_t _tag, ranges::span<AssemblyItem const> _i
|
||||
{
|
||||
assertThrow(_items.size() > 0, OptimizerException, "");
|
||||
|
||||
if (_items.back() != Instruction::JUMP && !SemanticInformation::terminatesControlFlow(_items.back()))
|
||||
if (_items.back().type() != Operation)
|
||||
return false;
|
||||
if (
|
||||
_items.back() != Instruction::JUMP &&
|
||||
!SemanticInformation::terminatesControlFlow(_items.back().instruction())
|
||||
)
|
||||
return false;
|
||||
|
||||
// Never inline tags that reference themselves.
|
||||
@ -213,7 +218,7 @@ optional<AssemblyItem> Inliner::shouldInline(size_t _tag, AssemblyItem const& _j
|
||||
// Inline small blocks, if the jump to it is ordinary or the blockExit is a terminating instruction.
|
||||
if (
|
||||
_jump.getJumpType() == AssemblyItem::JumpType::Ordinary ||
|
||||
SemanticInformation::terminatesControlFlow(blockExit)
|
||||
SemanticInformation::terminatesControlFlow(blockExit.instruction())
|
||||
)
|
||||
{
|
||||
static AssemblyItems const jumpPattern = {
|
||||
|
@ -135,14 +135,6 @@ bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
|
||||
}
|
||||
}
|
||||
|
||||
bool SemanticInformation::terminatesControlFlow(AssemblyItem const& _item)
|
||||
{
|
||||
if (_item.type() != Operation)
|
||||
return false;
|
||||
else
|
||||
return terminatesControlFlow(_item.instruction());
|
||||
}
|
||||
|
||||
bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
@ -158,14 +150,6 @@ bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
|
||||
}
|
||||
}
|
||||
|
||||
bool SemanticInformation::reverts(AssemblyItem const& _item)
|
||||
{
|
||||
if (_item.type() != Operation)
|
||||
return false;
|
||||
else
|
||||
return reverts(_item.instruction());
|
||||
}
|
||||
|
||||
bool SemanticInformation::reverts(Instruction _instruction)
|
||||
{
|
||||
switch (_instruction)
|
||||
|
@ -55,9 +55,7 @@ struct SemanticInformation
|
||||
static bool isSwapInstruction(AssemblyItem const& _item);
|
||||
static bool isJumpInstruction(AssemblyItem const& _item);
|
||||
static bool altersControlFlow(AssemblyItem const& _item);
|
||||
static bool terminatesControlFlow(AssemblyItem const& _item);
|
||||
static bool terminatesControlFlow(Instruction _instruction);
|
||||
static bool reverts(AssemblyItem const& _item);
|
||||
static bool reverts(Instruction _instruction);
|
||||
/// @returns false if the value put on the stack by _item depends on anything else than
|
||||
/// the information in the current block header, memory, storage or stack.
|
||||
|
@ -133,6 +133,10 @@ set(sources
|
||||
interface/CompilerStack.cpp
|
||||
interface/CompilerStack.h
|
||||
interface/DebugSettings.h
|
||||
interface/FileReader.cpp
|
||||
interface/FileReader.h
|
||||
interface/ImportRemapper.cpp
|
||||
interface/ImportRemapper.h
|
||||
interface/GasEstimator.cpp
|
||||
interface/GasEstimator.h
|
||||
interface/Natspec.cpp
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#include <libsolutil/Algorithms.h>
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity::langutil;
|
||||
@ -344,7 +344,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
||||
{
|
||||
errorString = "Data location must be " +
|
||||
util::joinHumanReadable(
|
||||
allowedDataLocations | boost::adaptors::transformed(locationToString),
|
||||
allowedDataLocations | ranges::views::transform(locationToString),
|
||||
", ",
|
||||
" or "
|
||||
);
|
||||
|
@ -71,7 +71,7 @@ bool DocStringTagParser::visit(VariableDeclaration const& _variable)
|
||||
if (_variable.isPublic())
|
||||
parseDocStrings(_variable, _variable.annotation(), {"dev", "notice", "return", "inheritdoc"}, "public state variables");
|
||||
else
|
||||
parseDocStrings(_variable, _variable.annotation(), {"dev", "inheritdoc"}, "non-public state variables");
|
||||
parseDocStrings(_variable, _variable.annotation(), {"dev", "notice", "inheritdoc"}, "non-public state variables");
|
||||
}
|
||||
else if (_variable.isFileLevelVariable())
|
||||
parseDocStrings(_variable, _variable.annotation(), {"dev"}, "file-level variables");
|
||||
|
@ -42,11 +42,11 @@
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/range/adaptor/sliced.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
#include <range/v3/view/enumerate.hpp>
|
||||
#include <range/v3/view/reverse.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <unordered_set>
|
||||
@ -227,7 +227,7 @@ string richIdentifier(Type const* _type)
|
||||
|
||||
string identifierList(vector<Type const*> const& _list)
|
||||
{
|
||||
return identifierList(_list | boost::adaptors::transformed(richIdentifier));
|
||||
return identifierList(_list | ranges::views::transform(richIdentifier));
|
||||
}
|
||||
|
||||
string identifierList(Type const* _type)
|
||||
@ -2374,7 +2374,7 @@ string StructType::signatureInExternalFunction(bool _structsByName) const
|
||||
else
|
||||
{
|
||||
TypePointers memberTypes = memoryMemberTypes();
|
||||
auto memberTypeStrings = memberTypes | boost::adaptors::transformed([&](Type const* _t) -> string
|
||||
auto memberTypeStrings = memberTypes | ranges::views::transform([&](Type const* _t) -> string
|
||||
{
|
||||
solAssert(_t, "Parameter should have external type.");
|
||||
auto t = _t->interfaceType(_structsByName);
|
||||
@ -3439,7 +3439,7 @@ string FunctionType::externalSignature() const
|
||||
|
||||
solAssert(extParams.message().empty(), extParams.message());
|
||||
|
||||
auto typeStrings = extParams.get() | boost::adaptors::transformed([&](Type const* _t) -> string
|
||||
auto typeStrings = extParams.get() | ranges::views::transform([&](Type const* _t) -> string
|
||||
{
|
||||
string typeName = _t->signatureInExternalFunction(inLibrary);
|
||||
|
||||
|
@ -1182,12 +1182,23 @@ string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _t
|
||||
function <functionName>(offset, length, end) -> array {
|
||||
array := <allocate>(<allocationSize>(length))
|
||||
let dst := array
|
||||
<storeLength>
|
||||
<?dynamic>
|
||||
mstore(array, length)
|
||||
dst := add(array, 0x20)
|
||||
</dynamic>
|
||||
let src := offset
|
||||
<staticBoundsCheck>
|
||||
if gt(add(src, mul(length, <stride>)), end) {
|
||||
<revertInvalidStride>
|
||||
}
|
||||
for { let i := 0 } lt(i, length) { i := add(i, 1) }
|
||||
{
|
||||
let elementPos := <retrieveElementPos>
|
||||
<?dynamicBase>
|
||||
let innerOffset := <load>(src)
|
||||
if gt(innerOffset, 0xffffffffffffffff) { <revertStringOffset> }
|
||||
let elementPos := add(offset, innerOffset)
|
||||
<!dynamicBase>
|
||||
let elementPos := src
|
||||
</dynamicBase>
|
||||
mstore(dst, <decodingFun>(elementPos, end))
|
||||
dst := add(dst, 0x20)
|
||||
src := add(src, <stride>)
|
||||
@ -1198,28 +1209,15 @@ string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _t
|
||||
templ("readableTypeName", _type.toString(true));
|
||||
templ("allocate", m_utils.allocationFunction());
|
||||
templ("allocationSize", m_utils.arrayAllocationSizeFunction(_type));
|
||||
string calldataStride = toCompactHexWithPrefix(_type.calldataStride());
|
||||
templ("stride", calldataStride);
|
||||
if (_type.isDynamicallySized())
|
||||
templ("storeLength", "mstore(array, length) dst := add(array, 0x20)");
|
||||
else
|
||||
templ("storeLength", "");
|
||||
if (_type.baseType()->isDynamicallyEncoded())
|
||||
{
|
||||
templ("staticBoundsCheck", "");
|
||||
string load = _fromMemory ? "mload" : "calldataload";
|
||||
templ("retrieveElementPos", "add(offset, " + load + "(src))");
|
||||
}
|
||||
else
|
||||
{
|
||||
templ("staticBoundsCheck", "if gt(add(src, mul(length, " +
|
||||
calldataStride +
|
||||
")), end) { " +
|
||||
revertReasonIfDebug("ABI decoding: invalid calldata array stride") +
|
||||
" }"
|
||||
);
|
||||
templ("retrieveElementPos", "src");
|
||||
}
|
||||
templ("stride", toCompactHexWithPrefix(_type.calldataStride()));
|
||||
templ("dynamic", _type.isDynamicallySized());
|
||||
templ("load", _fromMemory ? "mload" : "calldataload");
|
||||
templ("dynamicBase", _type.baseType()->isDynamicallyEncoded());
|
||||
templ(
|
||||
"revertInvalidStride",
|
||||
revertReasonIfDebug("ABI decoding: invalid calldata array stride")
|
||||
);
|
||||
templ("revertStringOffset", revertReasonIfDebug("ABI decoding: invalid calldata array offset"));
|
||||
templ("decodingFun", abiDecodingFunction(*_type.baseType(), _fromMemory, false));
|
||||
return templ.render();
|
||||
});
|
||||
|
@ -870,7 +870,7 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
<callValueCheck>
|
||||
<?+params>let <params> := </+params> <abiDecode>(4, calldatasize())
|
||||
<?+retParams>let <retParams> := </+retParams> <function>(<params>)
|
||||
let memPos := <allocate>(0)
|
||||
let memPos := <allocateUnbounded>()
|
||||
let memEnd := <abiEncode>(memPos <?+retParams>,</+retParams> <retParams>)
|
||||
return(memPos, sub(memEnd, memPos))
|
||||
}
|
||||
@ -919,7 +919,7 @@ string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
|
||||
else
|
||||
solAssert(false, "Unexpected declaration for function!");
|
||||
|
||||
templ["allocate"] = m_utils.allocationFunction();
|
||||
templ["allocateUnbounded"] = m_utils.allocateUnboundedFunction();
|
||||
templ["abiEncode"] = abiFunctions.tupleEncoder(type->returnParameterTypes(), type->returnParameterTypes(), _contract.isLibrary());
|
||||
}
|
||||
t("cases", functions);
|
||||
|
@ -47,7 +47,7 @@
|
||||
#include <libsolutil/FunctionSelector.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@ -1037,7 +1037,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
|
||||
templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes));
|
||||
templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs));
|
||||
templ("log", "log" + to_string(indexedArgs.size()));
|
||||
templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | boost::adaptors::transformed([&](auto const& _arg) {
|
||||
templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | ranges::views::transform([&](auto const& _arg) {
|
||||
return _arg.commaSeparatedList();
|
||||
})));
|
||||
m_code << templ.render();
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <libsolidity/codegen/ir/Common.h>
|
||||
#include <libsolidity/codegen/ir/IRVariable.h>
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
|
||||
using namespace std;
|
||||
|
@ -61,8 +61,6 @@ BMC::BMC(
|
||||
|
||||
void BMC::analyze(SourceUnit const& _source, map<ASTNode const*, set<VerificationTargetType>> _solvedTargets)
|
||||
{
|
||||
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
||||
|
||||
/// This is currently used to abort analysis of SourceUnits
|
||||
/// containing file level functions or constants.
|
||||
if (SMTEncoder::analyze(_source))
|
||||
|
@ -76,8 +76,6 @@ CHC::CHC(
|
||||
|
||||
void CHC::analyze(SourceUnit const& _source)
|
||||
{
|
||||
solAssert(_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker), "");
|
||||
|
||||
/// This is currently used to abort analysis of SourceUnits
|
||||
/// containing file level functions or constants.
|
||||
if (SMTEncoder::analyze(_source))
|
||||
@ -1430,10 +1428,6 @@ void CHC::verificationTargetEncountered(
|
||||
return;
|
||||
|
||||
solAssert(m_currentContract || m_currentFunction, "");
|
||||
SourceUnit const* source = m_currentContract ? sourceUnitContaining(*m_currentContract) : sourceUnitContaining(*m_currentFunction);
|
||||
solAssert(source, "");
|
||||
if (!source->annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
||||
return;
|
||||
|
||||
bool scopeIsFunction = m_currentFunction && !m_currentFunction->isConstructor();
|
||||
auto errorId = newErrorId();
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <libsmtutil/Z3Interface.h>
|
||||
#endif
|
||||
|
||||
#include <range/v3/algorithm/any_of.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::util;
|
||||
@ -34,6 +36,7 @@ ModelChecker::ModelChecker(
|
||||
ReadCallback::Callback const& _smtCallback,
|
||||
smtutil::SMTSolverChoice _enabledSolvers
|
||||
):
|
||||
m_errorReporter(_errorReporter),
|
||||
m_settings(_settings),
|
||||
m_context(),
|
||||
m_bmc(m_context, _errorReporter, _smtlib2Responses, _smtCallback, _enabledSolvers, m_settings),
|
||||
@ -41,9 +44,43 @@ ModelChecker::ModelChecker(
|
||||
{
|
||||
}
|
||||
|
||||
// TODO This should be removed for 0.9.0.
|
||||
void ModelChecker::enableAllEnginesIfPragmaPresent(vector<shared_ptr<SourceUnit>> const& _sources)
|
||||
{
|
||||
bool hasPragma = ranges::any_of(_sources, [](auto _source) {
|
||||
return _source && _source->annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker);
|
||||
});
|
||||
if (hasPragma)
|
||||
m_settings.engine = ModelCheckerEngine::All();
|
||||
}
|
||||
|
||||
void ModelChecker::analyze(SourceUnit const& _source)
|
||||
{
|
||||
if (!_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
||||
// TODO This should be removed for 0.9.0.
|
||||
if (_source.annotation().experimentalFeatures.count(ExperimentalFeature::SMTChecker))
|
||||
{
|
||||
PragmaDirective const* smtPragma = nullptr;
|
||||
for (auto node: _source.nodes())
|
||||
if (auto pragma = dynamic_pointer_cast<PragmaDirective>(node))
|
||||
if (
|
||||
pragma->literals().size() >= 2 &&
|
||||
pragma->literals().at(1) == "SMTChecker"
|
||||
)
|
||||
{
|
||||
smtPragma = pragma.get();
|
||||
break;
|
||||
}
|
||||
solAssert(smtPragma, "");
|
||||
m_errorReporter.warning(
|
||||
5523_error,
|
||||
smtPragma->location(),
|
||||
"The SMTChecker pragma has been deprecated and will be removed in the future. "
|
||||
"Please use the \"model checker engine\" compiler setting to activate the SMTChecker instead. "
|
||||
"If the pragma is enabled, all engines will be used."
|
||||
);
|
||||
}
|
||||
|
||||
if (m_settings.engine.none())
|
||||
return;
|
||||
|
||||
if (m_settings.engine.chc)
|
||||
|
@ -55,6 +55,9 @@ public:
|
||||
smtutil::SMTSolverChoice _enabledSolvers = smtutil::SMTSolverChoice::All()
|
||||
);
|
||||
|
||||
// TODO This should be removed for 0.9.0.
|
||||
void enableAllEnginesIfPragmaPresent(std::vector<std::shared_ptr<SourceUnit>> const& _sources);
|
||||
|
||||
void analyze(SourceUnit const& _sources);
|
||||
|
||||
/// This is used if the SMT solver is not directly linked into this binary.
|
||||
@ -66,6 +69,8 @@ public:
|
||||
static smtutil::SMTSolverChoice availableSolvers();
|
||||
|
||||
private:
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
|
||||
ModelCheckerSettings m_settings;
|
||||
|
||||
/// Stores the context of the encoding.
|
||||
|
@ -69,7 +69,7 @@ struct ModelCheckerTargets
|
||||
|
||||
struct ModelCheckerSettings
|
||||
{
|
||||
ModelCheckerEngine engine = ModelCheckerEngine::All();
|
||||
ModelCheckerEngine engine = ModelCheckerEngine::None();
|
||||
ModelCheckerTargets targets = ModelCheckerTargets::All();
|
||||
std::optional<unsigned> timeout;
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
|
||||
#include <libsolidity/analysis/ControlFlowAnalyzer.h>
|
||||
#include <libsolidity/analysis/ControlFlowGraph.h>
|
||||
@ -196,33 +197,13 @@ void CompilerStack::findAndReportCyclicContractDependencies()
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping)
|
||||
{
|
||||
auto eq = find(_remapping.begin(), _remapping.end(), '=');
|
||||
if (eq == _remapping.end())
|
||||
return {};
|
||||
|
||||
auto colon = find(_remapping.begin(), eq, ':');
|
||||
|
||||
Remapping r;
|
||||
|
||||
r.context = colon == eq ? string() : string(_remapping.begin(), colon);
|
||||
r.prefix = colon == eq ? string(_remapping.begin(), eq) : string(colon + 1, eq);
|
||||
r.target = string(eq + 1, _remapping.end());
|
||||
|
||||
if (r.prefix.empty())
|
||||
return {};
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void CompilerStack::setRemappings(vector<Remapping> const& _remappings)
|
||||
void CompilerStack::setRemappings(vector<ImportRemapper::Remapping> _remappings)
|
||||
{
|
||||
if (m_stackState >= ParsedAndImported)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set remappings before parsing."));
|
||||
for (auto const& remapping: _remappings)
|
||||
solAssert(!remapping.prefix.empty(), "");
|
||||
m_remappings = _remappings;
|
||||
m_importRemapper.setRemappings(move(_remappings));
|
||||
}
|
||||
|
||||
void CompilerStack::setViaIR(bool _viaIR)
|
||||
@ -312,7 +293,7 @@ void CompilerStack::reset(bool _keepSettings)
|
||||
m_unhandledSMTLib2Queries.clear();
|
||||
if (!_keepSettings)
|
||||
{
|
||||
m_remappings.clear();
|
||||
m_importRemapper.clear();
|
||||
m_libraries.clear();
|
||||
m_viaIR = false;
|
||||
m_evmVersion = langutil::EVMVersion();
|
||||
@ -566,6 +547,7 @@ bool CompilerStack::analyze()
|
||||
if (noErrors)
|
||||
{
|
||||
ModelChecker modelChecker(m_errorReporter, m_smtlib2Responses, m_modelCheckerSettings, m_readFile, m_enabledSMTSolvers);
|
||||
modelChecker.enableAllEnginesIfPragmaPresent(applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; }));
|
||||
for (Source const* source: m_sourceOrder)
|
||||
if (source->ast)
|
||||
modelChecker.analyze(*source->ast);
|
||||
@ -889,7 +871,7 @@ evmasm::LinkerObject const& CompilerStack::runtimeObject(string const& _contract
|
||||
}
|
||||
|
||||
/// TODO: cache this string
|
||||
string CompilerStack::assemblyString(string const& _contractName, StringMap _sourceCodes) const
|
||||
string CompilerStack::assemblyString(string const& _contractName, StringMap const& _sourceCodes) const
|
||||
{
|
||||
if (m_stackState != CompilationSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
|
||||
@ -1170,43 +1152,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string
|
||||
string CompilerStack::applyRemapping(string const& _path, string const& _context)
|
||||
{
|
||||
solAssert(m_stackState < ParsedAndImported, "");
|
||||
// Try to find the longest prefix match in all remappings that are active in the current context.
|
||||
auto isPrefixOf = [](string const& _a, string const& _b)
|
||||
{
|
||||
if (_a.length() > _b.length())
|
||||
return false;
|
||||
return std::equal(_a.begin(), _a.end(), _b.begin());
|
||||
};
|
||||
|
||||
size_t longestPrefix = 0;
|
||||
size_t longestContext = 0;
|
||||
string bestMatchTarget;
|
||||
|
||||
for (auto const& redir: m_remappings)
|
||||
{
|
||||
string context = util::sanitizePath(redir.context);
|
||||
string prefix = util::sanitizePath(redir.prefix);
|
||||
|
||||
// Skip if current context is closer
|
||||
if (context.length() < longestContext)
|
||||
continue;
|
||||
// Skip if redir.context is not a prefix of _context
|
||||
if (!isPrefixOf(context, _context))
|
||||
continue;
|
||||
// Skip if we already have a closer prefix match.
|
||||
if (prefix.length() < longestPrefix && context.length() == longestContext)
|
||||
continue;
|
||||
// Skip if the prefix does not match.
|
||||
if (!isPrefixOf(prefix, _path))
|
||||
continue;
|
||||
|
||||
longestContext = context.length();
|
||||
longestPrefix = prefix.length();
|
||||
bestMatchTarget = util::sanitizePath(redir.target);
|
||||
}
|
||||
string path = bestMatchTarget;
|
||||
path.append(_path.begin() + static_cast<string::difference_type>(longestPrefix), _path.end());
|
||||
return path;
|
||||
return m_importRemapper.apply(_path, _context);
|
||||
}
|
||||
|
||||
void CompilerStack::resolveImports()
|
||||
@ -1584,7 +1530,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const
|
||||
|
||||
meta["settings"]["remappings"] = Json::arrayValue;
|
||||
set<string> remappings;
|
||||
for (auto const& r: m_remappings)
|
||||
for (auto const& r: m_importRemapper.remappings())
|
||||
remappings.insert(r.context + ":" + r.prefix + "=" + r.target);
|
||||
for (auto const& r: remappings)
|
||||
meta["settings"]["remappings"].append(r);
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include <libsolidity/analysis/FunctionCallGraph.h>
|
||||
#include <libsolidity/interface/ReadFile.h>
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
#include <libsolidity/interface/OptimiserSettings.h>
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libsolidity/interface/DebugSettings.h>
|
||||
@ -111,13 +112,6 @@ public:
|
||||
None
|
||||
};
|
||||
|
||||
struct Remapping
|
||||
{
|
||||
std::string context;
|
||||
std::string prefix;
|
||||
std::string target;
|
||||
};
|
||||
|
||||
/// Creates a new compiler stack.
|
||||
/// @param _readFile callback used to read files for import statements. Must return
|
||||
/// and must not emit exceptions.
|
||||
@ -139,12 +133,9 @@ public:
|
||||
/// all settings are reset as well.
|
||||
void reset(bool _keepSettings = false);
|
||||
|
||||
// Parses a remapping of the format "context:prefix=target".
|
||||
static std::optional<Remapping> parseRemapping(std::string const& _remapping);
|
||||
|
||||
/// Sets path remappings.
|
||||
/// Must be set before parsing.
|
||||
void setRemappings(std::vector<Remapping> const& _remappings);
|
||||
void setRemappings(std::vector<ImportRemapper::Remapping> _remappings);
|
||||
|
||||
/// Sets library addresses. Addresses are cleared iff @a _libraries is missing.
|
||||
/// Must be set before parsing.
|
||||
@ -312,7 +303,7 @@ public:
|
||||
/// @return a verbose text representation of the assembly.
|
||||
/// @arg _sourceCodes is the map of input files to source code strings
|
||||
/// Prerequisite: Successful compilation.
|
||||
std::string assemblyString(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;
|
||||
std::string assemblyString(std::string const& _contractName, StringMap const& _sourceCodes = StringMap()) const;
|
||||
|
||||
/// @returns a JSON representation of the assembly.
|
||||
/// @arg _sourceCodes is the map of input files to source code strings
|
||||
@ -487,9 +478,7 @@ private:
|
||||
bool m_generateIR = false;
|
||||
bool m_generateEwasm = false;
|
||||
std::map<std::string, util::h160> m_libraries;
|
||||
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
||||
/// "context:prefix=target"
|
||||
std::vector<Remapping> m_remappings;
|
||||
ImportRemapper m_importRemapper;
|
||||
std::map<std::string const, Source> m_sources;
|
||||
// if imported, store AST-JSONS for each filename
|
||||
std::map<std::string, Json::Value> m_sourceJsons;
|
||||
|
97
libsolidity/interface/FileReader.cpp
Normal file
97
libsolidity/interface/FileReader.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
#include <libsolidity/interface/FileReader.h>
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <libsolutil/Exceptions.h>
|
||||
|
||||
using solidity::frontend::ReadCallback;
|
||||
using solidity::langutil::InternalCompilerError;
|
||||
using solidity::util::errinfo_comment;
|
||||
using solidity::util::readFileAsString;
|
||||
using std::string;
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source)
|
||||
{
|
||||
m_sourceCodes[_path.generic_string()] = std::move(_source);
|
||||
}
|
||||
|
||||
void FileReader::setSources(StringMap _sources)
|
||||
{
|
||||
m_sourceCodes = std::move(_sources);
|
||||
}
|
||||
|
||||
ReadCallback::Result FileReader::readFile(string const& _kind, string const& _sourceUnitName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_kind != ReadCallback::kindString(ReadCallback::Kind::ReadFile))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment(
|
||||
"ReadFile callback used as callback kind " +
|
||||
_kind
|
||||
));
|
||||
string strippedSourceUnitName = _sourceUnitName;
|
||||
if (strippedSourceUnitName.find("file://") == 0)
|
||||
strippedSourceUnitName.erase(0, 7);
|
||||
|
||||
auto canonicalPath = boost::filesystem::weakly_canonical(m_basePath / strippedSourceUnitName);
|
||||
bool isAllowed = false;
|
||||
for (auto const& allowedDir: m_allowedDirectories)
|
||||
{
|
||||
// If dir is a prefix of boostPath, we are fine.
|
||||
if (
|
||||
std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) &&
|
||||
std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin())
|
||||
)
|
||||
{
|
||||
isAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isAllowed)
|
||||
return ReadCallback::Result{false, "File outside of allowed directories."};
|
||||
|
||||
if (!boost::filesystem::exists(canonicalPath))
|
||||
return ReadCallback::Result{false, "File not found."};
|
||||
|
||||
if (!boost::filesystem::is_regular_file(canonicalPath))
|
||||
return ReadCallback::Result{false, "Not a valid file."};
|
||||
|
||||
// NOTE: we ignore the FileNotFound exception as we manually check above
|
||||
auto contents = readFileAsString(canonicalPath.string());
|
||||
m_sourceCodes[_sourceUnitName] = contents;
|
||||
return ReadCallback::Result{true, contents};
|
||||
}
|
||||
catch (util::Exception const& _exception)
|
||||
{
|
||||
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return ReadCallback::Result{false, "Unknown exception in read callback."};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
97
libsolidity/interface/FileReader.h
Normal file
97
libsolidity/interface/FileReader.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
#include <libsolidity/interface/ReadFile.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
/// FileReader - used for progressively loading source code.
|
||||
///
|
||||
/// It is used in solc to load files from CLI parameters, stdin, or from JSON and
|
||||
/// also used in the solc language server where solc is a long running process.
|
||||
class FileReader
|
||||
{
|
||||
public:
|
||||
using StringMap = std::map<SourceUnitName, SourceCode>;
|
||||
using PathMap = std::map<SourceUnitName, boost::filesystem::path>;
|
||||
using FileSystemPathSet = std::set<boost::filesystem::path>;
|
||||
|
||||
/// Constructs a FileReader with a base path and a set of allowed directories that
|
||||
/// will be used when requesting files from this file reader instance.
|
||||
explicit FileReader(
|
||||
boost::filesystem::path _basePath = {},
|
||||
FileSystemPathSet _allowedDirectories = {}
|
||||
):
|
||||
m_basePath(std::move(_basePath)),
|
||||
m_allowedDirectories(std::move(_allowedDirectories)),
|
||||
m_sourceCodes()
|
||||
{}
|
||||
|
||||
void setBasePath(boost::filesystem::path _path) { m_basePath = std::move(_path); }
|
||||
boost::filesystem::path const& basePath() const noexcept { return m_basePath; }
|
||||
|
||||
void allowDirectory(boost::filesystem::path _path) { m_allowedDirectories.insert(std::move(_path)); }
|
||||
FileSystemPathSet const& allowedDirectories() const noexcept { return m_allowedDirectories; }
|
||||
|
||||
StringMap const& sourceCodes() const noexcept { return m_sourceCodes; }
|
||||
|
||||
/// Retrieves the source code for a given source unit ID.
|
||||
SourceCode const& sourceCode(SourceUnitName const& _sourceUnitName) const { return m_sourceCodes.at(_sourceUnitName); }
|
||||
|
||||
/// Resets all sources to the given map of source unit ID to source codes.
|
||||
/// Does not enforce @a allowedDirectories().
|
||||
void setSources(StringMap _sources);
|
||||
|
||||
/// Adds the source code for a given source unit ID.
|
||||
/// Does not enforce @a allowedDirectories().
|
||||
void setSource(boost::filesystem::path const& _path, SourceCode _source);
|
||||
|
||||
/// Receives a @p _sourceUnitName that refers to a source unit in compiler's virtual filesystem
|
||||
/// and attempts to interpret it as a path and read the corresponding file from disk.
|
||||
/// The read will only succeed if the canonical path of the file is within one of the @a allowedDirectories().
|
||||
/// @param _kind must be equal to "source". Other values are not supported.
|
||||
/// @return Content of the loaded file or an error message. If the operation succeeds, a copy of
|
||||
/// the content is retained in @a sourceCodes() under the key of @a _sourceUnitName. If the key
|
||||
/// already exists, previous content is discarded.
|
||||
frontend::ReadCallback::Result readFile(std::string const& _kind, std::string const& _sourceUnitName);
|
||||
|
||||
frontend::ReadCallback::Callback reader()
|
||||
{
|
||||
return [this](std::string const& _kind, std::string const& _path) { return readFile(_kind, _path); };
|
||||
}
|
||||
|
||||
private:
|
||||
/// Base path, used for resolving relative paths in imports.
|
||||
boost::filesystem::path m_basePath;
|
||||
|
||||
/// list of allowed directories to read files from
|
||||
FileSystemPathSet m_allowedDirectories;
|
||||
|
||||
/// map of input files to source code strings
|
||||
StringMap m_sourceCodes;
|
||||
};
|
||||
|
||||
}
|
100
libsolidity/interface/ImportRemapper.cpp
Normal file
100
libsolidity/interface/ImportRemapper.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
#include <libsolutil/CommonIO.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
using std::equal;
|
||||
using std::move;
|
||||
using std::optional;
|
||||
using std::string;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
void ImportRemapper::setRemappings(vector<Remapping> _remappings)
|
||||
{
|
||||
for (auto const& remapping: _remappings)
|
||||
solAssert(!remapping.prefix.empty(), "");
|
||||
m_remappings = move(_remappings);
|
||||
}
|
||||
|
||||
SourceUnitName ImportRemapper::apply(ImportPath const& _path, string const& _context) const
|
||||
{
|
||||
// Try to find the longest prefix match in all remappings that are active in the current context.
|
||||
auto isPrefixOf = [](string const& _a, string const& _b)
|
||||
{
|
||||
if (_a.length() > _b.length())
|
||||
return false;
|
||||
return equal(_a.begin(), _a.end(), _b.begin());
|
||||
};
|
||||
|
||||
size_t longestPrefix = 0;
|
||||
size_t longestContext = 0;
|
||||
string bestMatchTarget;
|
||||
|
||||
for (auto const& redir: m_remappings)
|
||||
{
|
||||
string context = util::sanitizePath(redir.context);
|
||||
string prefix = util::sanitizePath(redir.prefix);
|
||||
|
||||
// Skip if current context is closer
|
||||
if (context.length() < longestContext)
|
||||
continue;
|
||||
// Skip if redir.context is not a prefix of _context
|
||||
if (!isPrefixOf(context, _context))
|
||||
continue;
|
||||
// Skip if we already have a closer prefix match.
|
||||
if (prefix.length() < longestPrefix && context.length() == longestContext)
|
||||
continue;
|
||||
// Skip if the prefix does not match.
|
||||
if (!isPrefixOf(prefix, _path))
|
||||
continue;
|
||||
|
||||
longestContext = context.length();
|
||||
longestPrefix = prefix.length();
|
||||
bestMatchTarget = util::sanitizePath(redir.target);
|
||||
}
|
||||
string path = bestMatchTarget;
|
||||
path.append(_path.begin() + static_cast<string::difference_type>(longestPrefix), _path.end());
|
||||
return path;
|
||||
}
|
||||
|
||||
optional<ImportRemapper::Remapping> ImportRemapper::parseRemapping(string const& _remapping)
|
||||
{
|
||||
auto eq = find(_remapping.begin(), _remapping.end(), '=');
|
||||
if (eq == _remapping.end())
|
||||
return {};
|
||||
|
||||
auto colon = find(_remapping.begin(), eq, ':');
|
||||
|
||||
Remapping r;
|
||||
|
||||
r.context = colon == eq ? string() : string(_remapping.begin(), colon);
|
||||
r.prefix = colon == eq ? string(_remapping.begin(), eq) : string(colon + 1, eq);
|
||||
r.target = string(eq + 1, _remapping.end());
|
||||
|
||||
if (r.prefix.empty())
|
||||
return {};
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
59
libsolidity/interface/ImportRemapper.h
Normal file
59
libsolidity/interface/ImportRemapper.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
// Some helper typedefs to make reading the signatures more self explaining.
|
||||
using SourceUnitName = std::string;
|
||||
using SourceCode = std::string;
|
||||
using ImportPath = std::string;
|
||||
|
||||
/// The ImportRemapper is being used on imported file paths for being remapped to source unit IDs before being loaded.
|
||||
class ImportRemapper
|
||||
{
|
||||
public:
|
||||
struct Remapping
|
||||
{
|
||||
std::string context;
|
||||
std::string prefix;
|
||||
std::string target;
|
||||
};
|
||||
|
||||
void clear() { m_remappings.clear(); }
|
||||
|
||||
void setRemappings(std::vector<Remapping> _remappings);
|
||||
std::vector<Remapping> const& remappings() const noexcept { return m_remappings; }
|
||||
|
||||
SourceUnitName apply(ImportPath const& _path, std::string const& _context) const;
|
||||
|
||||
// Parses a remapping of the format "context:prefix=target".
|
||||
static std::optional<Remapping> parseRemapping(std::string const& _remapping);
|
||||
|
||||
private:
|
||||
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
||||
/// "context:prefix=target"
|
||||
std::vector<Remapping> m_remappings = {};
|
||||
};
|
||||
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include <libsolidity/interface/StandardCompiler.h>
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
|
||||
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||
#include <libyul/AssemblyStack.h>
|
||||
@ -810,7 +811,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
|
||||
{
|
||||
if (!remapping.isString())
|
||||
return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings");
|
||||
if (auto r = CompilerStack::parseRemapping(remapping.asString()))
|
||||
if (auto r = ImportRemapper::parseRemapping(remapping.asString()))
|
||||
ret.remappings.emplace_back(std::move(*r));
|
||||
else
|
||||
return formatFatalError("JSONError", "Invalid remapping: \"" + remapping.asString() + "\"");
|
||||
@ -941,7 +942,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
|
||||
compilerStack.setViaIR(_inputsAndSettings.viaIR);
|
||||
compilerStack.setEVMVersion(_inputsAndSettings.evmVersion);
|
||||
compilerStack.setParserErrorRecovery(_inputsAndSettings.parserErrorRecovery);
|
||||
compilerStack.setRemappings(_inputsAndSettings.remappings);
|
||||
compilerStack.setRemappings(move(_inputsAndSettings.remappings));
|
||||
compilerStack.setOptimiserSettings(std::move(_inputsAndSettings.optimiserSettings));
|
||||
compilerStack.setRevertStringBehaviour(_inputsAndSettings.revertStrings);
|
||||
compilerStack.setLibraries(_inputsAndSettings.libraries);
|
||||
|
@ -64,7 +64,7 @@ private:
|
||||
std::map<std::string, std::string> sources;
|
||||
std::map<util::h256, std::string> smtLib2Responses;
|
||||
langutil::EVMVersion evmVersion;
|
||||
std::vector<CompilerStack::Remapping> remappings;
|
||||
std::vector<ImportRemapper::Remapping> remappings;
|
||||
RevertStrings revertStrings = RevertStrings::Default;
|
||||
OptimiserSettings optimiserSettings = OptimiserSettings::minimal();
|
||||
std::map<std::string, util::h160> libraries;
|
||||
|
@ -721,9 +721,6 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
ASTPointer<TypeName> type = _lookAheadArrayType ? _lookAheadArrayType : parseTypeName();
|
||||
nodeFactory.setEndPositionFromNode(type);
|
||||
|
||||
if (_options.kind == VarDeclKind::Other && documentation != nullptr)
|
||||
parserError(2837_error, "Only state variables or file-level variables can have a docstring.");
|
||||
|
||||
if (dynamic_cast<FunctionTypeName*>(type.get()) && _options.kind == VarDeclKind::State && m_scanner->currentToken() == Token::LBrace)
|
||||
fatalParserError(
|
||||
2915_error,
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include <libsolutil/CommonData.h>
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <boost/range/adaptor/reversed.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
@ -285,6 +285,7 @@ variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
|
||||
return identifier;
|
||||
}
|
||||
case Token::StringLiteral:
|
||||
case Token::HexStringLiteral:
|
||||
case Token::Number:
|
||||
case Token::TrueLiteral:
|
||||
case Token::FalseLiteral:
|
||||
@ -293,6 +294,7 @@ variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
|
||||
switch (currentToken())
|
||||
{
|
||||
case Token::StringLiteral:
|
||||
case Token::HexStringLiteral:
|
||||
kind = LiteralKind::String;
|
||||
break;
|
||||
case Token::Number:
|
||||
@ -324,9 +326,6 @@ variant<Literal, Identifier> Parser::parseLiteralOrIdentifier()
|
||||
|
||||
return literal;
|
||||
}
|
||||
case Token::HexStringLiteral:
|
||||
fatalParserError(3772_error, "Hex literals are not valid in this context.");
|
||||
break;
|
||||
case Token::Illegal:
|
||||
fatalParserError(1465_error, "Illegal token: " + to_string(m_scanner->currentError()));
|
||||
break;
|
||||
|
@ -30,7 +30,8 @@
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
@ -83,7 +84,7 @@ string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) c
|
||||
{
|
||||
string out = "let ";
|
||||
out += boost::algorithm::join(
|
||||
_variableDeclaration.variables | boost::adaptors::transformed(
|
||||
_variableDeclaration.variables | ranges::views::transform(
|
||||
[this](TypedName argument) { return formatTypedName(argument); }
|
||||
),
|
||||
", "
|
||||
@ -101,7 +102,7 @@ string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) con
|
||||
yulAssert(!_functionDefinition.name.empty(), "Invalid function name.");
|
||||
string out = "function " + _functionDefinition.name.str() + "(";
|
||||
out += boost::algorithm::join(
|
||||
_functionDefinition.parameters | boost::adaptors::transformed(
|
||||
_functionDefinition.parameters | ranges::views::transform(
|
||||
[this](TypedName argument) { return formatTypedName(argument); }
|
||||
),
|
||||
", "
|
||||
@ -111,7 +112,7 @@ string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) con
|
||||
{
|
||||
out += " -> ";
|
||||
out += boost::algorithm::join(
|
||||
_functionDefinition.returnVariables | boost::adaptors::transformed(
|
||||
_functionDefinition.returnVariables | ranges::views::transform(
|
||||
[this](TypedName argument) { return formatTypedName(argument); }
|
||||
),
|
||||
", "
|
||||
@ -126,7 +127,7 @@ string AsmPrinter::operator()(FunctionCall const& _functionCall) const
|
||||
return
|
||||
(*this)(_functionCall.functionName) + "(" +
|
||||
boost::algorithm::join(
|
||||
_functionCall.arguments | boost::adaptors::transformed([&](auto&& _node) { return std::visit(*this, _node); }),
|
||||
_functionCall.arguments | ranges::views::transform([&](auto&& _node) { return std::visit(*this, _node); }),
|
||||
", " ) +
|
||||
")";
|
||||
}
|
||||
@ -194,7 +195,7 @@ string AsmPrinter::operator()(Block const& _block) const
|
||||
if (_block.statements.empty())
|
||||
return "{ }";
|
||||
string body = boost::algorithm::join(
|
||||
_block.statements | boost::adaptors::transformed([&](auto&& _node) { return std::visit(*this, _node); }),
|
||||
_block.statements | ranges::views::transform([&](auto&& _node) { return std::visit(*this, _node); }),
|
||||
"\n"
|
||||
);
|
||||
if (body.size() < 30 && body.find('\n') == string::npos)
|
||||
|
@ -65,6 +65,8 @@ add_library(yul
|
||||
backends/evm/EVMMetrics.h
|
||||
backends/evm/NoOutputAssembly.h
|
||||
backends/evm/NoOutputAssembly.cpp
|
||||
backends/evm/VariableReferenceCounter.h
|
||||
backends/evm/VariableReferenceCounter.cpp
|
||||
backends/wasm/EVMToEwasmTranslator.cpp
|
||||
backends/wasm/EVMToEwasmTranslator.h
|
||||
backends/wasm/BinaryTransform.cpp
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <libsolutil/Exceptions.h>
|
||||
#include <libsolutil/Assertions.h>
|
||||
|
||||
#include <libyul/YulString.h>
|
||||
|
||||
namespace solidity::yul
|
||||
{
|
||||
|
||||
@ -32,6 +34,23 @@ struct OptimizerException: virtual YulException {};
|
||||
struct CodegenException: virtual YulException {};
|
||||
struct YulAssertion: virtual YulException {};
|
||||
|
||||
struct StackTooDeepError: virtual YulException
|
||||
{
|
||||
StackTooDeepError(YulString _variable, int _depth, std::string const& _message):
|
||||
variable(_variable), depth(_depth)
|
||||
{
|
||||
*this << util::errinfo_comment(_message);
|
||||
}
|
||||
StackTooDeepError(YulString _functionName, YulString _variable, int _depth, std::string const& _message):
|
||||
functionName(_functionName), variable(_variable), depth(_depth)
|
||||
{
|
||||
*this << util::errinfo_comment(_message);
|
||||
}
|
||||
YulString functionName;
|
||||
YulString variable;
|
||||
int depth;
|
||||
};
|
||||
|
||||
/// Assertion that throws an YulAssertion containing the given description if it is not met.
|
||||
#define yulAssert(CONDITION, DESCRIPTION) \
|
||||
assertThrow(CONDITION, ::solidity::yul::YulAssertion, DESCRIPTION)
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
#include <libyul/Scope.h>
|
||||
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
|
@ -25,8 +25,6 @@
|
||||
|
||||
#include <libyul/YulString.h>
|
||||
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Common code generator for translating Yul / inline assembly to EVM and EVM1.5.
|
||||
* Code generator for translating Yul / inline assembly to EVM.
|
||||
*/
|
||||
|
||||
#include <libyul/backends/evm/EVMCodeTransform.h>
|
||||
@ -25,6 +25,8 @@
|
||||
#include <libyul/AsmAnalysisInfo.h>
|
||||
#include <libyul/Utilities.h>
|
||||
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <range/v3/view/reverse.hpp>
|
||||
@ -42,62 +44,6 @@ using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
using namespace solidity::util;
|
||||
|
||||
void VariableReferenceCounter::operator()(Identifier const& _identifier)
|
||||
{
|
||||
increaseRefIfFound(_identifier.name);
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::operator()(FunctionDefinition const& _function)
|
||||
{
|
||||
Scope* originalScope = m_scope;
|
||||
|
||||
yulAssert(m_info.virtualBlocks.at(&_function), "");
|
||||
m_scope = m_info.scopes.at(m_info.virtualBlocks.at(&_function).get()).get();
|
||||
yulAssert(m_scope, "Variable scope does not exist.");
|
||||
|
||||
for (auto const& v: _function.returnVariables)
|
||||
increaseRefIfFound(v.name);
|
||||
|
||||
VariableReferenceCounter{m_context, m_info}(_function.body);
|
||||
|
||||
m_scope = originalScope;
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::operator()(ForLoop const& _forLoop)
|
||||
{
|
||||
Scope* originalScope = m_scope;
|
||||
// Special scoping rules.
|
||||
m_scope = m_info.scopes.at(&_forLoop.pre).get();
|
||||
|
||||
walkVector(_forLoop.pre.statements);
|
||||
visit(*_forLoop.condition);
|
||||
(*this)(_forLoop.body);
|
||||
(*this)(_forLoop.post);
|
||||
|
||||
m_scope = originalScope;
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::operator()(Block const& _block)
|
||||
{
|
||||
Scope* originalScope = m_scope;
|
||||
m_scope = m_info.scopes.at(&_block).get();
|
||||
|
||||
ASTWalker::operator()(_block);
|
||||
|
||||
m_scope = originalScope;
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::increaseRefIfFound(YulString _variableName)
|
||||
{
|
||||
m_scope->lookup(_variableName, GenericVisitor{
|
||||
[&](Scope::Variable const& _var)
|
||||
{
|
||||
++m_context.variableReferences[&_var];
|
||||
},
|
||||
[](Scope::Function const&) { }
|
||||
});
|
||||
}
|
||||
|
||||
CodeTransform::CodeTransform(
|
||||
AbstractAssembly& _assembly,
|
||||
AsmAnalysisInfo& _analysisInfo,
|
||||
@ -127,7 +73,7 @@ CodeTransform::CodeTransform(
|
||||
// initialize
|
||||
m_context = make_shared<Context>();
|
||||
if (m_allowStackOpt)
|
||||
VariableReferenceCounter{*m_context, m_info}(_block);
|
||||
m_context->variableReferences = VariableReferenceCounter::run(m_info, _block);
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,8 +180,8 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
||||
if (m_assembly.stackHeight() - *it > 17)
|
||||
continue;
|
||||
foundUnusedSlot = true;
|
||||
m_unusedStackSlots.erase(it);
|
||||
auto slot = static_cast<size_t>(*it);
|
||||
m_unusedStackSlots.erase(it);
|
||||
m_context->variableStackHeights[&var] = slot;
|
||||
if (size_t heightDiff = variableHeightDiff(var, varName, true))
|
||||
m_assembly.appendInstruction(evmasm::swapInstruction(static_cast<unsigned>(heightDiff - 1)));
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Common code generator for translating Yul / inline assembly to EVM and EVM1.5.
|
||||
* Code generator for translating Yul / inline assembly to EVM.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -24,6 +24,7 @@
|
||||
#include <libyul/backends/evm/EVMAssembly.h>
|
||||
|
||||
#include <libyul/backends/evm/EVMDialect.h>
|
||||
#include <libyul/backends/evm/VariableReferenceCounter.h>
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/AST.h>
|
||||
#include <libyul/Scope.h>
|
||||
@ -41,23 +42,6 @@ namespace solidity::yul
|
||||
struct AsmAnalysisInfo;
|
||||
class EVMAssembly;
|
||||
|
||||
struct StackTooDeepError: virtual YulException
|
||||
{
|
||||
StackTooDeepError(YulString _variable, int _depth, std::string const& _message):
|
||||
variable(_variable), depth(_depth)
|
||||
{
|
||||
*this << util::errinfo_comment(_message);
|
||||
}
|
||||
StackTooDeepError(YulString _functionName, YulString _variable, int _depth, std::string const& _message):
|
||||
functionName(_functionName), variable(_variable), depth(_depth)
|
||||
{
|
||||
*this << util::errinfo_comment(_message);
|
||||
}
|
||||
YulString functionName;
|
||||
YulString variable;
|
||||
int depth;
|
||||
};
|
||||
|
||||
struct CodeTransformContext
|
||||
{
|
||||
std::map<Scope::Function const*, AbstractAssembly::LabelID> functionEntryIDs;
|
||||
@ -79,38 +63,6 @@ struct CodeTransformContext
|
||||
std::stack<ForLoopLabels> forLoopStack;
|
||||
};
|
||||
|
||||
/**
|
||||
* Counts the number of references to a variable. This includes actual (read) references
|
||||
* but also assignments to the variable. It does not include the declaration itself or
|
||||
* function parameters, but it does include function return parameters.
|
||||
*
|
||||
* This component can handle multiple variables of the same name.
|
||||
*
|
||||
* Can only be applied to strict assembly.
|
||||
*/
|
||||
class VariableReferenceCounter: public yul::ASTWalker
|
||||
{
|
||||
public:
|
||||
explicit VariableReferenceCounter(
|
||||
CodeTransformContext& _context,
|
||||
AsmAnalysisInfo const& _assemblyInfo
|
||||
): m_context(_context), m_info(_assemblyInfo)
|
||||
{}
|
||||
|
||||
public:
|
||||
void operator()(Identifier const& _identifier) override;
|
||||
void operator()(FunctionDefinition const&) override;
|
||||
void operator()(ForLoop const&) override;
|
||||
void operator()(Block const& _block) override;
|
||||
|
||||
private:
|
||||
void increaseRefIfFound(YulString _variableName);
|
||||
|
||||
CodeTransformContext& m_context;
|
||||
AsmAnalysisInfo const& m_info;
|
||||
Scope* m_scope = nullptr;
|
||||
};
|
||||
|
||||
class CodeTransform
|
||||
{
|
||||
public:
|
||||
|
83
libyul/backends/evm/VariableReferenceCounter.cpp
Normal file
83
libyul/backends/evm/VariableReferenceCounter.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Counts the number of references to a variable.
|
||||
*/
|
||||
#include <libyul/backends/evm/VariableReferenceCounter.h>
|
||||
#include <libyul/AsmAnalysisInfo.h>
|
||||
#include <libyul/AST.h>
|
||||
|
||||
#include <libsolutil/Visitor.h>
|
||||
|
||||
using namespace solidity::yul;
|
||||
|
||||
void VariableReferenceCounter::operator()(Identifier const& _identifier)
|
||||
{
|
||||
increaseRefIfFound(_identifier.name);
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::operator()(FunctionDefinition const& _function)
|
||||
{
|
||||
Scope* originalScope = m_scope;
|
||||
|
||||
yulAssert(m_info.virtualBlocks.at(&_function), "");
|
||||
m_scope = m_info.scopes.at(m_info.virtualBlocks.at(&_function).get()).get();
|
||||
yulAssert(m_scope, "Variable scope does not exist.");
|
||||
|
||||
for (auto const& v: _function.returnVariables)
|
||||
increaseRefIfFound(v.name);
|
||||
|
||||
(*this)(_function.body);
|
||||
|
||||
m_scope = originalScope;
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::operator()(ForLoop const& _forLoop)
|
||||
{
|
||||
Scope* originalScope = m_scope;
|
||||
// Special scoping rules.
|
||||
m_scope = m_info.scopes.at(&_forLoop.pre).get();
|
||||
|
||||
walkVector(_forLoop.pre.statements);
|
||||
visit(*_forLoop.condition);
|
||||
(*this)(_forLoop.body);
|
||||
(*this)(_forLoop.post);
|
||||
|
||||
m_scope = originalScope;
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::operator()(Block const& _block)
|
||||
{
|
||||
Scope* originalScope = m_scope;
|
||||
m_scope = m_info.scopes.at(&_block).get();
|
||||
|
||||
ASTWalker::operator()(_block);
|
||||
|
||||
m_scope = originalScope;
|
||||
}
|
||||
|
||||
void VariableReferenceCounter::increaseRefIfFound(YulString _variableName)
|
||||
{
|
||||
m_scope->lookup(_variableName, util::GenericVisitor{
|
||||
[&](Scope::Variable const& _var)
|
||||
{
|
||||
++m_variableReferences[&_var];
|
||||
},
|
||||
[](Scope::Function const&) { }
|
||||
});
|
||||
}
|
68
libyul/backends/evm/VariableReferenceCounter.h
Normal file
68
libyul/backends/evm/VariableReferenceCounter.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
/**
|
||||
* Counts the number of references to a variable.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/Scope.h>
|
||||
|
||||
namespace solidity::yul
|
||||
{
|
||||
struct AsmAnalysisInfo;
|
||||
|
||||
/**
|
||||
* Counts the number of references to a variable. This includes actual (read) references
|
||||
* but also assignments to the variable. It does not include the declaration itself or
|
||||
* function parameters, but it does include function return parameters.
|
||||
*
|
||||
* This component can handle multiple variables of the same name.
|
||||
*
|
||||
* Can only be applied to strict assembly.
|
||||
*/
|
||||
struct VariableReferenceCounter: public yul::ASTWalker
|
||||
{
|
||||
public:
|
||||
static std::map<Scope::Variable const*, unsigned> run(AsmAnalysisInfo const& _assemblyInfo, Block const& _block)
|
||||
{
|
||||
VariableReferenceCounter variableReferenceCounter(_assemblyInfo);
|
||||
variableReferenceCounter(_block);
|
||||
return std::move(variableReferenceCounter.m_variableReferences);
|
||||
}
|
||||
|
||||
protected:
|
||||
void operator()(Block const& _block) override;
|
||||
void operator()(Identifier const& _identifier) override;
|
||||
void operator()(FunctionDefinition const&) override;
|
||||
void operator()(ForLoop const&) override;
|
||||
|
||||
private:
|
||||
explicit VariableReferenceCounter(
|
||||
AsmAnalysisInfo const& _assemblyInfo
|
||||
): m_info(_assemblyInfo)
|
||||
{}
|
||||
|
||||
void increaseRefIfFound(YulString _variableName);
|
||||
|
||||
AsmAnalysisInfo const& m_info;
|
||||
Scope* m_scope = nullptr;
|
||||
std::map<Scope::Variable const*, unsigned> m_variableReferences;
|
||||
};
|
||||
|
||||
}
|
@ -26,8 +26,6 @@
|
||||
#include <libsolutil/Visitor.h>
|
||||
#include <libsolutil/LEB128.h>
|
||||
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
||||
#include <range/v3/view/map.hpp>
|
||||
#include <range/v3/view/reverse.hpp>
|
||||
|
||||
|
@ -31,7 +31,8 @@
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
@ -67,7 +68,7 @@ string TextTransform::run(wasm::Module const& _module)
|
||||
{
|
||||
ret += " (import \"" + imp.module + "\" \"" + imp.externalName + "\" (func $" + imp.internalName;
|
||||
if (!imp.paramTypes.empty())
|
||||
ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | boost::adaptors::transformed(encodeType), " ", " ") + ")";
|
||||
ret += " (param" + joinHumanReadablePrefixed(imp.paramTypes | ranges::views::transform(encodeType), " ", " ") + ")";
|
||||
if (imp.returnType)
|
||||
ret += " (result " + encodeType(*imp.returnType) + ")";
|
||||
ret += "))\n";
|
||||
|
@ -93,8 +93,8 @@ case $(uname -s) in
|
||||
10.15)
|
||||
echo "Installing solidity dependencies on macOS 10.15 Catalina."
|
||||
;;
|
||||
11.0 | 11.1)
|
||||
echo "Installing solidity dependencies on macOS 11.0 / 11.1 Big Sur."
|
||||
11.0 | 11.1 | 11.2)
|
||||
echo "Installing solidity dependencies on macOS 11.0 / 11.1 / 11.2 Big Sur."
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported macOS version."
|
||||
|
@ -39,19 +39,15 @@ prepare_workdir()
|
||||
prepare_workdir
|
||||
download_antlr4
|
||||
|
||||
if [[ ! -f "${WORKDIR}/target/SolidityParser.class" ]] || \
|
||||
[ "${GRAMMAR_FILE}" -nt "${WORKDIR}/target/SolidityParser.class" ]
|
||||
then
|
||||
echo "Creating parser"
|
||||
(
|
||||
cd "${ROOT_DIR}"/docs/grammar
|
||||
# Create lexer/parser from grammar
|
||||
java -jar "${ANTLR_JAR}" Solidity.g4 SolidityLexer.g4 -o "${WORKDIR}/src/"
|
||||
echo "Creating parser"
|
||||
(
|
||||
cd "${ROOT_DIR}"/docs/grammar
|
||||
# Create lexer/parser from grammar
|
||||
java -jar "${ANTLR_JAR}" SolidityParser.g4 SolidityLexer.g4 -o "${WORKDIR}/src/"
|
||||
|
||||
# Compile lexer/parser sources
|
||||
javac -classpath "${ANTLR_JAR}" "${WORKDIR}/src/"*.java -d "${WORKDIR}/target/"
|
||||
)
|
||||
fi
|
||||
# Compile lexer/parser sources
|
||||
javac -classpath "${ANTLR_JAR}" "${WORKDIR}/src/"*.java -d "${WORKDIR}/target/"
|
||||
)
|
||||
|
||||
# Run tests
|
||||
failed_count=0
|
||||
@ -67,11 +63,11 @@ test_file()
|
||||
local output
|
||||
if [[ "${solOrYul}" == "sol" ]]; then
|
||||
output=$(
|
||||
java \
|
||||
grep -v "^==== ExternalSource:" "${SOL_FILE}" | java \
|
||||
-classpath "${ANTLR_JAR}:${WORKDIR}/target/" \
|
||||
"org.antlr.v4.gui.TestRig" \
|
||||
Solidity \
|
||||
sourceUnit <"${SOL_FILE}" 2>&1
|
||||
sourceUnit 2>&1
|
||||
)
|
||||
else
|
||||
output=$(
|
||||
@ -113,7 +109,7 @@ while IFS='' read -r line
|
||||
do
|
||||
SOL_FILES+=("$line")
|
||||
done < <(
|
||||
grep -riL -E \
|
||||
grep --include "*.sol" -riL -E \
|
||||
"^\/\/ (Syntax|Type|Declaration)Error|^\/\/ ParserError (1684|2837|3716|3997|5333|6275|6281|6933|7319)|^==== Source:" \
|
||||
"${ROOT_DIR}/test/libsolidity/syntaxTests" \
|
||||
"${ROOT_DIR}/test/libsolidity/semanticTests" |
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "solidity/BuildInfo.h"
|
||||
#include "license.h"
|
||||
|
||||
#include <libsolidity/interface/FileReader.h>
|
||||
#include <libsolidity/interface/Version.h>
|
||||
#include <libsolidity/parsing/Parser.h>
|
||||
#include <libsolidity/ast/ASTJsonConverter.h>
|
||||
@ -35,6 +36,7 @@
|
||||
#include <libsolidity/interface/StandardCompiler.h>
|
||||
#include <libsolidity/interface/GasEstimator.h>
|
||||
#include <libsolidity/interface/DebugSettings.h>
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
#include <libsolidity/interface/StorageLayout.h>
|
||||
|
||||
#include <libyul/AssemblyStack.h>
|
||||
@ -57,12 +59,15 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <range/v3/view/map.hpp>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/range/adaptor/transformed.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
#ifdef _WIN32 // windows
|
||||
#include <io.h>
|
||||
#define isatty _isatty
|
||||
@ -579,7 +584,7 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
|
||||
auto eq = find(path.begin(), path.end(), '=');
|
||||
if (eq != path.end())
|
||||
{
|
||||
if (auto r = CompilerStack::parseRemapping(path))
|
||||
if (auto r = ImportRemapper::parseRemapping(path))
|
||||
{
|
||||
m_remappings.emplace_back(std::move(*r));
|
||||
path = string(eq + 1, path.end());
|
||||
@ -622,14 +627,16 @@ bool CommandLineInterface::readInputFilesAndConfigureRemappings()
|
||||
}
|
||||
|
||||
// NOTE: we ignore the FileNotFound exception as we manually check above
|
||||
m_sourceCodes[infile.generic_string()] = readFileAsString(infile.string());
|
||||
m_fileReader.setSource(infile, readFileAsString(infile.string()));
|
||||
path = boost::filesystem::canonical(infile).string();
|
||||
}
|
||||
m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename());
|
||||
m_fileReader.allowDirectory(boost::filesystem::path(path).remove_filename());
|
||||
}
|
||||
|
||||
if (addStdin)
|
||||
m_sourceCodes[g_stdinFileName] = readStandardInput();
|
||||
if (m_sourceCodes.size() == 0)
|
||||
m_fileReader.setSource(g_stdinFileName, readStandardInput());
|
||||
|
||||
if (m_fileReader.sourceCodes().size() == 0)
|
||||
{
|
||||
serr() << "No input files given. If you wish to use the standard input please specify \"-\" explicitly." << endl;
|
||||
return false;
|
||||
@ -738,10 +745,10 @@ map<string, Json::Value> CommandLineInterface::parseAstFromInput()
|
||||
map<string, Json::Value> sourceJsons;
|
||||
map<string, string> tmpSources;
|
||||
|
||||
for (auto const& srcPair: m_sourceCodes)
|
||||
for (SourceCode const& sourceCode: m_fileReader.sourceCodes() | ranges::views::values)
|
||||
{
|
||||
Json::Value ast;
|
||||
astAssert(jsonParseStrict(srcPair.second, ast), "Input file could not be parsed to JSON");
|
||||
astAssert(jsonParseStrict(sourceCode, ast), "Input file could not be parsed to JSON");
|
||||
astAssert(ast.isMember("sources"), "Invalid Format for import-JSON: Must have 'sources'-object");
|
||||
|
||||
for (auto& src: ast["sources"].getMemberNames())
|
||||
@ -756,7 +763,8 @@ map<string, Json::Value> CommandLineInterface::parseAstFromInput()
|
||||
}
|
||||
}
|
||||
|
||||
m_sourceCodes = std::move(tmpSources);
|
||||
m_fileReader.setSources(tmpSources);
|
||||
|
||||
return sourceJsons;
|
||||
}
|
||||
|
||||
@ -1047,7 +1055,7 @@ General Information)").c_str(),
|
||||
smtCheckerOptions.add_options()
|
||||
(
|
||||
g_strModelCheckerEngine.c_str(),
|
||||
po::value<string>()->value_name("all,bmc,chc,none")->default_value("all"),
|
||||
po::value<string>()->value_name("all,bmc,chc,none")->default_value("none"),
|
||||
"Select model checker engine."
|
||||
)
|
||||
(
|
||||
@ -1162,58 +1170,6 @@ General Information)").c_str(),
|
||||
|
||||
bool CommandLineInterface::processInput()
|
||||
{
|
||||
ReadCallback::Callback fileReader = [this](string const& _kind, string const& _path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_kind != ReadCallback::kindString(ReadCallback::Kind::ReadFile))
|
||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment(
|
||||
"ReadFile callback used as callback kind " +
|
||||
_kind
|
||||
));
|
||||
string validPath = _path;
|
||||
if (validPath.find("file://") == 0)
|
||||
validPath.erase(0, 7);
|
||||
|
||||
auto const path = m_basePath / validPath;
|
||||
auto canonicalPath = boost::filesystem::weakly_canonical(path);
|
||||
bool isAllowed = false;
|
||||
for (auto const& allowedDir: m_allowedDirectories)
|
||||
{
|
||||
// If dir is a prefix of boostPath, we are fine.
|
||||
if (
|
||||
std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) &&
|
||||
std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin())
|
||||
)
|
||||
{
|
||||
isAllowed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isAllowed)
|
||||
return ReadCallback::Result{false, "File outside of allowed directories."};
|
||||
|
||||
if (!boost::filesystem::exists(canonicalPath))
|
||||
return ReadCallback::Result{false, "File not found."};
|
||||
|
||||
if (!boost::filesystem::is_regular_file(canonicalPath))
|
||||
return ReadCallback::Result{false, "Not a valid file."};
|
||||
|
||||
// NOTE: we ignore the FileNotFound exception as we manually check above
|
||||
auto contents = readFileAsString(canonicalPath.string());
|
||||
m_sourceCodes[path.generic_string()] = contents;
|
||||
return ReadCallback::Result{true, contents};
|
||||
}
|
||||
catch (Exception const& _exception)
|
||||
{
|
||||
return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)};
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return ReadCallback::Result{false, "Unknown exception in read callback."};
|
||||
}
|
||||
};
|
||||
|
||||
if (m_args.count(g_argBasePath))
|
||||
{
|
||||
boost::filesystem::path const fspath{m_args[g_argBasePath].as<string>()};
|
||||
@ -1222,9 +1178,7 @@ bool CommandLineInterface::processInput()
|
||||
serr() << "Base path must be a directory: \"" << fspath << "\"\n";
|
||||
return false;
|
||||
}
|
||||
m_basePath = fspath;
|
||||
if (!contains(m_allowedDirectories, fspath))
|
||||
m_allowedDirectories.push_back(fspath);
|
||||
m_fileReader.setBasePath(fspath);
|
||||
}
|
||||
|
||||
if (m_args.count(g_argAllowPaths))
|
||||
@ -1239,7 +1193,7 @@ bool CommandLineInterface::processInput()
|
||||
// it.
|
||||
if (filesystem_path.filename() == ".")
|
||||
filesystem_path.remove_filename();
|
||||
m_allowedDirectories.push_back(filesystem_path);
|
||||
m_fileReader.allowDirectory(filesystem_path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1297,7 +1251,7 @@ bool CommandLineInterface::processInput()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
StandardCompiler compiler(fileReader);
|
||||
StandardCompiler compiler(m_fileReader.reader());
|
||||
sout() << compiler.compile(std::move(input)) << endl;
|
||||
return true;
|
||||
}
|
||||
@ -1489,7 +1443,7 @@ bool CommandLineInterface::processInput()
|
||||
if (m_args.count(g_argModelCheckerTimeout))
|
||||
m_modelCheckerSettings.timeout = m_args[g_argModelCheckerTimeout].as<unsigned>();
|
||||
|
||||
m_compiler = make_unique<CompilerStack>(fileReader);
|
||||
m_compiler = make_unique<CompilerStack>(m_fileReader.reader());
|
||||
|
||||
SourceReferenceFormatter formatter(serr(false), m_coloredOutput, m_withErrorIds);
|
||||
|
||||
@ -1563,7 +1517,7 @@ bool CommandLineInterface::processInput()
|
||||
}
|
||||
else
|
||||
{
|
||||
m_compiler->setSources(m_sourceCodes);
|
||||
m_compiler->setSources(m_fileReader.sourceCodes());
|
||||
if (m_args.count(g_argErrorRecovery))
|
||||
m_compiler->setParserErrorRecovery(true);
|
||||
}
|
||||
@ -1713,7 +1667,7 @@ void CommandLineInterface::handleCombinedJSON()
|
||||
if (requests.count(g_strAst))
|
||||
{
|
||||
output[g_strSources] = Json::Value(Json::objectValue);
|
||||
for (auto const& sourceCode: m_sourceCodes)
|
||||
for (auto const& sourceCode: m_fileReader.sourceCodes())
|
||||
{
|
||||
ASTJsonConverter converter(m_compiler->state(), m_compiler->sourceIndices());
|
||||
output[g_strSources][sourceCode.first] = Json::Value(Json::objectValue);
|
||||
@ -1736,12 +1690,12 @@ void CommandLineInterface::handleAst()
|
||||
return;
|
||||
|
||||
vector<ASTNode const*> asts;
|
||||
for (auto const& sourceCode: m_sourceCodes)
|
||||
for (auto const& sourceCode: m_fileReader.sourceCodes())
|
||||
asts.push_back(&m_compiler->ast(sourceCode.first));
|
||||
|
||||
if (m_args.count(g_argOutputDir))
|
||||
{
|
||||
for (auto const& sourceCode: m_sourceCodes)
|
||||
for (auto const& sourceCode: m_fileReader.sourceCodes())
|
||||
{
|
||||
stringstream data;
|
||||
string postfix = "";
|
||||
@ -1754,7 +1708,7 @@ void CommandLineInterface::handleAst()
|
||||
else
|
||||
{
|
||||
sout() << "JSON AST (compact format):" << endl << endl;
|
||||
for (auto const& sourceCode: m_sourceCodes)
|
||||
for (auto const& sourceCode: m_fileReader.sourceCodes())
|
||||
{
|
||||
sout() << endl << "======= " << sourceCode.first << " =======" << endl;
|
||||
ASTJsonConverter(m_compiler->state(), m_compiler->sourceIndices()).print(sout(), m_compiler->ast(sourceCode.first));
|
||||
@ -1795,7 +1749,9 @@ bool CommandLineInterface::link()
|
||||
replacement += "__";
|
||||
librariesReplacements[replacement] = library.second;
|
||||
}
|
||||
for (auto& src: m_sourceCodes)
|
||||
|
||||
FileReader::StringMap sourceCodes = m_fileReader.sourceCodes();
|
||||
for (auto& src: sourceCodes)
|
||||
{
|
||||
auto end = src.second.end();
|
||||
for (auto it = src.second.begin(); it != end;)
|
||||
@ -1830,12 +1786,14 @@ bool CommandLineInterface::link()
|
||||
while (!src.second.empty() && *prev(src.second.end()) == '\n')
|
||||
src.second.resize(src.second.size() - 1);
|
||||
}
|
||||
m_fileReader.setSources(move(sourceCodes));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandLineInterface::writeLinkedFiles()
|
||||
{
|
||||
for (auto const& src: m_sourceCodes)
|
||||
for (auto const& src: m_fileReader.sourceCodes())
|
||||
if (src.first == g_stdinFileName)
|
||||
sout() << src.second << endl;
|
||||
else
|
||||
@ -1879,7 +1837,7 @@ bool CommandLineInterface::assemble(
|
||||
|
||||
bool successful = true;
|
||||
map<string, yul::AssemblyStack> assemblyStacks;
|
||||
for (auto const& src: m_sourceCodes)
|
||||
for (auto const& src: m_fileReader.sourceCodes())
|
||||
{
|
||||
OptimiserSettings settings = _optimize ? OptimiserSettings::full() : OptimiserSettings::minimal();
|
||||
if (_yulOptimiserSteps.has_value())
|
||||
@ -1930,7 +1888,7 @@ bool CommandLineInterface::assemble(
|
||||
if (!successful)
|
||||
return false;
|
||||
|
||||
for (auto const& src: m_sourceCodes)
|
||||
for (auto const& src: m_fileReader.sourceCodes())
|
||||
{
|
||||
string machine =
|
||||
_targetMachine == yul::AssemblyStack::Machine::EVM ? "EVM" :
|
||||
@ -2042,7 +2000,7 @@ void CommandLineInterface::outputCompilationResults()
|
||||
if (m_args.count(g_argAsmJson))
|
||||
ret = jsonPrettyPrint(removeNullMembers(m_compiler->assemblyJSON(contract)));
|
||||
else
|
||||
ret = m_compiler->assemblyString(contract, m_sourceCodes);
|
||||
ret = m_compiler->assemblyString(contract, m_fileReader.sourceCodes());
|
||||
|
||||
if (m_args.count(g_argOutputDir))
|
||||
{
|
||||
@ -2090,7 +2048,7 @@ size_t CommandLineInterface::countEnabledOptions(vector<string> const& _optionNa
|
||||
string CommandLineInterface::joinOptionNames(vector<string> const& _optionNames, string _separator)
|
||||
{
|
||||
return boost::algorithm::join(
|
||||
_optionNames | boost::adaptors::transformed([](string const& _option){ return "--" + _option; }),
|
||||
_optionNames | ranges::views::transform([](string const& _option){ return "--" + _option; }),
|
||||
_separator
|
||||
);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/DebugSettings.h>
|
||||
#include <libsolidity/interface/FileReader.h>
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
@ -112,16 +114,12 @@ private:
|
||||
|
||||
bool m_onlyLink = false;
|
||||
|
||||
FileReader m_fileReader;
|
||||
|
||||
/// Compiler arguments variable map
|
||||
boost::program_options::variables_map m_args;
|
||||
/// map of input files to source code strings
|
||||
std::map<std::string, std::string> m_sourceCodes;
|
||||
/// list of remappings
|
||||
std::vector<frontend::CompilerStack::Remapping> m_remappings;
|
||||
/// list of allowed directories to read files from
|
||||
std::vector<boost::filesystem::path> m_allowedDirectories;
|
||||
/// Base path, used for resolving relative paths in imports.
|
||||
boost::filesystem::path m_basePath;
|
||||
std::vector<ImportRemapper::Remapping> m_remappings;
|
||||
/// map of library names to addresses
|
||||
std::map<std::string, util::h160> m_libraries;
|
||||
/// Solidity compiler stack
|
||||
|
@ -162,7 +162,7 @@ function test_solc_behaviour()
|
||||
sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1<AUXDATA REMOVED>/' "$stdout_path"
|
||||
sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path"
|
||||
sed -i.bak -e 's/\(Unimplemented feature error.* in \).*$/\1<FILENAME REMOVED>/' "$stderr_path"
|
||||
sed -i.bak -e 's/"version": "[^"]*"/"version": "<VERSION REMOVED>"/' "$stdout_path"
|
||||
sed -i.bak -e 's/"version":[ ]*"[^"]*"/"version": "<VERSION REMOVED>"/' "$stdout_path"
|
||||
|
||||
# Remove bytecode (but not linker references). Since non-JSON output is unstructured,
|
||||
# use metadata markers for detection to have some confidence that it's actually bytecode
|
||||
@ -190,7 +190,7 @@ function test_solc_behaviour()
|
||||
then
|
||||
printError "Incorrect exit code. Expected $exit_code_expected but got $exitCode."
|
||||
|
||||
[[ $exit_code_expectation_file != "" ]] && ask_expectation_update "$exit_code_expected" "$exit_code_expectation_file"
|
||||
[[ $exit_code_expectation_file != "" ]] && ask_expectation_update "$exitCode" "$exit_code_expectation_file"
|
||||
[[ $exit_code_expectation_file == "" ]] && exit 1
|
||||
fi
|
||||
|
||||
|
1
test/cmdlineTests/ast_compact_json_with_base_path/args
Normal file
1
test/cmdlineTests/ast_compact_json_with_base_path/args
Normal file
@ -0,0 +1 @@
|
||||
--ast-compact-json --base-path . --allow-paths .
|
4
test/cmdlineTests/ast_compact_json_with_base_path/c.sol
Normal file
4
test/cmdlineTests/ast_compact_json_with_base_path/c.sol
Normal file
@ -0,0 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C {}
|
@ -0,0 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
import "./c.sol";
|
91
test/cmdlineTests/ast_compact_json_with_base_path/output
Normal file
91
test/cmdlineTests/ast_compact_json_with_base_path/output
Normal file
@ -0,0 +1,91 @@
|
||||
JSON AST (compact format):
|
||||
|
||||
|
||||
======= ast_compact_json_with_base_path/c.sol =======
|
||||
{
|
||||
"absolutePath": "ast_compact_json_with_base_path/c.sol",
|
||||
"exportedSymbols":
|
||||
{
|
||||
"C":
|
||||
[
|
||||
5
|
||||
]
|
||||
},
|
||||
"id": 6,
|
||||
"license": "GPL-3.0",
|
||||
"nodeType": "SourceUnit",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"id": 4,
|
||||
"literals":
|
||||
[
|
||||
"solidity",
|
||||
">=",
|
||||
"0.0"
|
||||
],
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "36:22:0"
|
||||
},
|
||||
{
|
||||
"abstract": false,
|
||||
"baseContracts": [],
|
||||
"contractDependencies": [],
|
||||
"contractKind": "contract",
|
||||
"fullyImplemented": true,
|
||||
"id": 5,
|
||||
"linearizedBaseContracts":
|
||||
[
|
||||
5
|
||||
],
|
||||
"name": "C",
|
||||
"nameLocation": "69:1:0",
|
||||
"nodeType": "ContractDefinition",
|
||||
"nodes": [],
|
||||
"scope": 6,
|
||||
"src": "60:13:0"
|
||||
}
|
||||
],
|
||||
"src": "36:38:0"
|
||||
}
|
||||
======= ast_compact_json_with_base_path/input.sol =======
|
||||
{
|
||||
"absolutePath": "ast_compact_json_with_base_path/input.sol",
|
||||
"exportedSymbols":
|
||||
{
|
||||
"C":
|
||||
[
|
||||
5
|
||||
]
|
||||
},
|
||||
"id": 3,
|
||||
"license": "GPL-3.0",
|
||||
"nodeType": "SourceUnit",
|
||||
"nodes":
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"literals":
|
||||
[
|
||||
"solidity",
|
||||
">=",
|
||||
"0.0"
|
||||
],
|
||||
"nodeType": "PragmaDirective",
|
||||
"src": "36:22:1"
|
||||
},
|
||||
{
|
||||
"absolutePath": "ast_compact_json_with_base_path/c.sol",
|
||||
"file": "./c.sol",
|
||||
"id": 2,
|
||||
"nameLocation": "-1:-1:-1",
|
||||
"nodeType": "ImportDirective",
|
||||
"scope": 3,
|
||||
"sourceUnit": 6,
|
||||
"src": "60:17:1",
|
||||
"symbolAliases": [],
|
||||
"unitAlias": ""
|
||||
}
|
||||
],
|
||||
"src": "36:42:1"
|
||||
}
|
1
test/cmdlineTests/combined_json_with_base_path/args
Normal file
1
test/cmdlineTests/combined_json_with_base_path/args
Normal file
@ -0,0 +1 @@
|
||||
--combined-json ast --base-path . --allow-paths .
|
4
test/cmdlineTests/combined_json_with_base_path/c.sol
Normal file
4
test/cmdlineTests/combined_json_with_base_path/c.sol
Normal file
@ -0,0 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
contract C {}
|
4
test/cmdlineTests/combined_json_with_base_path/input.sol
Normal file
4
test/cmdlineTests/combined_json_with_base_path/input.sol
Normal file
@ -0,0 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
|
||||
import "./c.sol";
|
1
test/cmdlineTests/combined_json_with_base_path/output
Normal file
1
test/cmdlineTests/combined_json_with_base_path/output
Normal file
@ -0,0 +1 @@
|
||||
{"contracts":{"combined_json_with_base_path/c.sol:C":{}},"sourceList":["combined_json_with_base_path/c.sol","combined_json_with_base_path/input.sol"],"sources":{"combined_json_with_base_path/c.sol":{"AST":{"absolutePath":"combined_json_with_base_path/c.sol","exportedSymbols":{"C":[5]},"id":6,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":4,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":5,"linearizedBaseContracts":[5],"name":"C","nameLocation":"69:1:0","nodeType":"ContractDefinition","nodes":[],"scope":6,"src":"60:13:0"}],"src":"36:38:0"}},"combined_json_with_base_path/input.sol":{"AST":{"absolutePath":"combined_json_with_base_path/input.sol","exportedSymbols":{"C":[5]},"id":3,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:1"},{"absolutePath":"combined_json_with_base_path/c.sol","file":"./c.sol","id":2,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":3,"sourceUnit":6,"src":"60:17:1","symbolAliases":[],"unitAlias":""}],"src":"36:42:1"}}},"version": "<VERSION REMOVED>"}
|
@ -39,7 +39,7 @@ object "C_81" {
|
||||
if callvalue() { revert(0, 0) }
|
||||
let param_0, param_1, param_2, param_3 := abi_decode_tuple_t_uint256t_uint256t_uint256t_uint256(4, calldatasize())
|
||||
let ret_0, ret_1, ret_2, ret_3 := fun_f_80(param_0, param_1, param_2, param_3)
|
||||
let memPos := allocate_memory(0)
|
||||
let memPos := allocate_unbounded()
|
||||
let memEnd := abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(memPos , ret_0, ret_1, ret_2, ret_3)
|
||||
return(memPos, sub(memEnd, memPos))
|
||||
}
|
||||
@ -108,11 +108,6 @@ object "C_81" {
|
||||
|
||||
}
|
||||
|
||||
function allocate_memory(size) -> memPtr {
|
||||
memPtr := allocate_unbounded()
|
||||
finalize_allocation(memPtr, size)
|
||||
}
|
||||
|
||||
function allocate_unbounded() -> memPtr {
|
||||
memPtr := mload(64)
|
||||
}
|
||||
@ -203,13 +198,6 @@ object "C_81" {
|
||||
converted := cleanup_t_int256(value)
|
||||
}
|
||||
|
||||
function finalize_allocation(memPtr, size) {
|
||||
let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))
|
||||
// protect against overflow
|
||||
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
|
||||
mstore(64, newFreePtr)
|
||||
}
|
||||
|
||||
function fun_f_80(var_a_4, var_b_6, var_c_8, var_d_10) -> var__13, var__15, var__17, var__19 {
|
||||
let zero_t_uint256_1 := zero_value_for_split_t_uint256()
|
||||
var__13 := zero_t_uint256_1
|
||||
@ -297,16 +285,6 @@ object "C_81" {
|
||||
revert(0, 0x24)
|
||||
}
|
||||
|
||||
function panic_error_0x41() {
|
||||
mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
|
||||
mstore(4, 0x41)
|
||||
revert(0, 0x24)
|
||||
}
|
||||
|
||||
function round_up_to_mul_of_32(value) -> result {
|
||||
result := and(add(value, 31), not(31))
|
||||
}
|
||||
|
||||
function shift_right_224_unsigned(value) -> newValue {
|
||||
newValue :=
|
||||
|
||||
|
@ -57,30 +57,23 @@ object "D_16" {
|
||||
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||
let _2 := datasize("C_3")
|
||||
let _3 := add(128, _2)
|
||||
if or(gt(_3, 0xffffffffffffffff), lt(_3, 128)) { panic_error_0x41() }
|
||||
if or(gt(_3, 0xffffffffffffffff), lt(_3, 128))
|
||||
{
|
||||
mstore(_1, shl(224, 0x4e487b71))
|
||||
mstore(4, 0x41)
|
||||
revert(_1, 0x24)
|
||||
}
|
||||
datacopy(128, dataoffset("C_3"), _2)
|
||||
if iszero(create(_1, 128, _2))
|
||||
{
|
||||
returndatacopy(_1, _1, returndatasize())
|
||||
revert(_1, returndatasize())
|
||||
}
|
||||
return(allocate_memory(), _1)
|
||||
return(mload(64), _1)
|
||||
}
|
||||
}
|
||||
revert(0, 0)
|
||||
}
|
||||
function allocate_memory() -> memPtr
|
||||
{
|
||||
memPtr := mload(64)
|
||||
if gt(memPtr, 0xffffffffffffffff) { panic_error_0x41() }
|
||||
mstore(64, memPtr)
|
||||
}
|
||||
function panic_error_0x41()
|
||||
{
|
||||
mstore(0, shl(224, 0x4e487b71))
|
||||
mstore(4, 0x41)
|
||||
revert(0, 0x24)
|
||||
}
|
||||
}
|
||||
object "C_3" {
|
||||
code {
|
||||
|
@ -27,7 +27,6 @@ object "D_12" {
|
||||
{
|
||||
if callvalue() { revert(_1, _1) }
|
||||
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||
mstore(64, 128)
|
||||
return(128, _1)
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ object "D_8" {
|
||||
{
|
||||
if callvalue() { revert(_1, _1) }
|
||||
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
|
||||
mstore(64, 128)
|
||||
return(128, _1)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ x = 0
|
||||
Transaction trace:
|
||||
test.constructor()
|
||||
test.f(0)
|
||||
--> model_checker_engine_all/input.sol:6:3:
|
||||
--> model_checker_engine_all/input.sol:5:3:
|
||||
|
|
||||
6 | assert(x > 0);
|
||||
5 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
|
@ -1,7 +1,7 @@
|
||||
Warning: BMC: Assertion violation happens here.
|
||||
--> model_checker_engine_bmc/input.sol:6:3:
|
||||
--> model_checker_engine_bmc/input.sol:5:3:
|
||||
|
|
||||
6 | assert(x > 0);
|
||||
5 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
x = 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
|
@ -6,7 +6,7 @@ x = 0
|
||||
Transaction trace:
|
||||
test.constructor()
|
||||
test.f(0)
|
||||
--> model_checker_engine_chc/input.sol:6:3:
|
||||
--> model_checker_engine_chc/input.sol:5:3:
|
||||
|
|
||||
6 | assert(x > 0);
|
||||
5 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Removed to yield a warning, otherwise CI test fails with the expectation
|
||||
// "no output requested"
|
||||
//pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
function f(uint x) public pure {
|
||||
assert(x > 0);
|
||||
|
@ -1 +1 @@
|
||||
--model-checker-targets all
|
||||
--model-checker-engine all --model-checker-targets all
|
||||
|
@ -8,9 +8,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 0)
|
||||
--> model_checker_targets_all/input.sol:8:3:
|
||||
--> model_checker_targets_all/input.sol:7:3:
|
||||
|
|
||||
8 | --x;
|
||||
7 | --x;
|
||||
| ^^^
|
||||
|
||||
Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here.
|
||||
@ -23,9 +23,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 2)
|
||||
--> model_checker_targets_all/input.sol:9:3:
|
||||
--> model_checker_targets_all/input.sol:8:3:
|
||||
|
|
||||
9 | x + type(uint).max;
|
||||
8 | x + type(uint).max;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Warning: CHC: Division by zero happens here.
|
||||
@ -38,10 +38,10 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all/input.sol:10:3:
|
||||
|
|
||||
10 | 2 / x;
|
||||
| ^^^^^
|
||||
--> model_checker_targets_all/input.sol:9:3:
|
||||
|
|
||||
9 | 2 / x;
|
||||
| ^^^^^
|
||||
|
||||
Warning: CHC: Assertion violation happens here.
|
||||
Counterexample:
|
||||
@ -53,9 +53,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all/input.sol:12:3:
|
||||
--> model_checker_targets_all/input.sol:11:3:
|
||||
|
|
||||
12 | assert(x > 0);
|
||||
11 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
Warning: CHC: Empty array "pop" happens here.
|
||||
@ -68,9 +68,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all/input.sol:13:3:
|
||||
--> model_checker_targets_all/input.sol:12:3:
|
||||
|
|
||||
13 | arr.pop();
|
||||
12 | arr.pop();
|
||||
| ^^^^^^^^^
|
||||
|
||||
Warning: CHC: Out of bounds access happens here.
|
||||
@ -83,22 +83,22 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all/input.sol:14:3:
|
||||
--> model_checker_targets_all/input.sol:13:3:
|
||||
|
|
||||
14 | arr[x];
|
||||
13 | arr[x];
|
||||
| ^^^^^^
|
||||
|
||||
Warning: BMC: Condition is always true.
|
||||
--> model_checker_targets_all/input.sol:7:11:
|
||||
--> model_checker_targets_all/input.sol:6:11:
|
||||
|
|
||||
7 | require(x >= 0);
|
||||
6 | require(x >= 0);
|
||||
| ^^^^^^
|
||||
Note: Callstack:
|
||||
|
||||
Warning: BMC: Insufficient funds happens here.
|
||||
--> model_checker_targets_all/input.sol:11:3:
|
||||
--> model_checker_targets_all/input.sol:10:3:
|
||||
|
|
||||
11 | a.transfer(x);
|
||||
10 | a.transfer(x);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
a = 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1,14 +1,14 @@
|
||||
Warning: BMC: Condition is always true.
|
||||
--> model_checker_targets_all_bmc/input.sol:7:11:
|
||||
--> model_checker_targets_all_bmc/input.sol:6:11:
|
||||
|
|
||||
7 | require(x >= 0);
|
||||
6 | require(x >= 0);
|
||||
| ^^^^^^
|
||||
Note: Callstack:
|
||||
|
||||
Warning: BMC: Underflow (resulting value less than 0) happens here.
|
||||
--> model_checker_targets_all_bmc/input.sol:8:3:
|
||||
--> model_checker_targets_all_bmc/input.sol:7:3:
|
||||
|
|
||||
8 | --x;
|
||||
7 | --x;
|
||||
| ^^^
|
||||
Note: Counterexample:
|
||||
<result> = (- 1)
|
||||
@ -19,9 +19,9 @@ Note: Callstack:
|
||||
Note:
|
||||
|
||||
Warning: BMC: Overflow (resulting value larger than 2**256 - 1) happens here.
|
||||
--> model_checker_targets_all_bmc/input.sol:9:3:
|
||||
--> model_checker_targets_all_bmc/input.sol:8:3:
|
||||
|
|
||||
9 | x + type(uint).max;
|
||||
8 | x + type(uint).max;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
<result> = 2**256
|
||||
@ -32,10 +32,10 @@ Note: Callstack:
|
||||
Note:
|
||||
|
||||
Warning: BMC: Division by zero happens here.
|
||||
--> model_checker_targets_all_bmc/input.sol:10:3:
|
||||
|
|
||||
10 | 2 / x;
|
||||
| ^^^^^
|
||||
--> model_checker_targets_all_bmc/input.sol:9:3:
|
||||
|
|
||||
9 | 2 / x;
|
||||
| ^^^^^
|
||||
Note: Counterexample:
|
||||
<result> = 0
|
||||
a = 0
|
||||
@ -45,9 +45,9 @@ Note: Callstack:
|
||||
Note:
|
||||
|
||||
Warning: BMC: Insufficient funds happens here.
|
||||
--> model_checker_targets_all_bmc/input.sol:11:3:
|
||||
--> model_checker_targets_all_bmc/input.sol:10:3:
|
||||
|
|
||||
11 | a.transfer(x);
|
||||
10 | a.transfer(x);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
a = 0
|
||||
@ -57,9 +57,9 @@ Note: Callstack:
|
||||
Note:
|
||||
|
||||
Warning: BMC: Assertion violation happens here.
|
||||
--> model_checker_targets_all_bmc/input.sol:12:3:
|
||||
--> model_checker_targets_all_bmc/input.sol:11:3:
|
||||
|
|
||||
12 | assert(x > 0);
|
||||
11 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
a = 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -8,9 +8,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 0)
|
||||
--> model_checker_targets_all_chc/input.sol:8:3:
|
||||
--> model_checker_targets_all_chc/input.sol:7:3:
|
||||
|
|
||||
8 | --x;
|
||||
7 | --x;
|
||||
| ^^^
|
||||
|
||||
Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here.
|
||||
@ -23,9 +23,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 2)
|
||||
--> model_checker_targets_all_chc/input.sol:9:3:
|
||||
--> model_checker_targets_all_chc/input.sol:8:3:
|
||||
|
|
||||
9 | x + type(uint).max;
|
||||
8 | x + type(uint).max;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Warning: CHC: Division by zero happens here.
|
||||
@ -38,10 +38,10 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all_chc/input.sol:10:3:
|
||||
|
|
||||
10 | 2 / x;
|
||||
| ^^^^^
|
||||
--> model_checker_targets_all_chc/input.sol:9:3:
|
||||
|
|
||||
9 | 2 / x;
|
||||
| ^^^^^
|
||||
|
||||
Warning: CHC: Assertion violation happens here.
|
||||
Counterexample:
|
||||
@ -53,9 +53,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all_chc/input.sol:12:3:
|
||||
--> model_checker_targets_all_chc/input.sol:11:3:
|
||||
|
|
||||
12 | assert(x > 0);
|
||||
11 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
Warning: CHC: Empty array "pop" happens here.
|
||||
@ -68,9 +68,9 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all_chc/input.sol:13:3:
|
||||
--> model_checker_targets_all_chc/input.sol:12:3:
|
||||
|
|
||||
13 | arr.pop();
|
||||
12 | arr.pop();
|
||||
| ^^^^^^^^^
|
||||
|
||||
Warning: CHC: Out of bounds access happens here.
|
||||
@ -83,7 +83,7 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_all_chc/input.sol:14:3:
|
||||
--> model_checker_targets_all_chc/input.sol:13:3:
|
||||
|
|
||||
14 | arr[x];
|
||||
13 | arr[x];
|
||||
| ^^^^^^
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1,7 +1,7 @@
|
||||
Warning: BMC: Assertion violation happens here.
|
||||
--> model_checker_targets_assert_bmc/input.sol:12:3:
|
||||
--> model_checker_targets_assert_bmc/input.sol:11:3:
|
||||
|
|
||||
12 | assert(x > 0);
|
||||
11 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
a = 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -8,7 +8,7 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_assert_chc/input.sol:12:3:
|
||||
--> model_checker_targets_assert_chc/input.sol:11:3:
|
||||
|
|
||||
12 | assert(x > 0);
|
||||
11 | assert(x > 0);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1,7 +1,7 @@
|
||||
Warning: BMC: Insufficient funds happens here.
|
||||
--> model_checker_targets_balance_bmc/input.sol:11:3:
|
||||
--> model_checker_targets_balance_bmc/input.sol:10:3:
|
||||
|
|
||||
11 | a.transfer(x);
|
||||
10 | a.transfer(x);
|
||||
| ^^^^^^^^^^^^^
|
||||
Note: Counterexample:
|
||||
a = 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1,5 +1,4 @@
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1,6 +1,6 @@
|
||||
Warning: BMC: Condition is always true.
|
||||
--> model_checker_targets_constant_condition_bmc/input.sol:7:11:
|
||||
--> model_checker_targets_constant_condition_bmc/input.sol:6:11:
|
||||
|
|
||||
7 | require(x >= 0);
|
||||
6 | require(x >= 0);
|
||||
| ^^^^^^
|
||||
Note: Callstack:
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1,5 +1,4 @@
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1,8 +1,8 @@
|
||||
Warning: BMC: Division by zero happens here.
|
||||
--> model_checker_targets_div_by_zero_bmc/input.sol:10:3:
|
||||
|
|
||||
10 | 2 / x;
|
||||
| ^^^^^
|
||||
--> model_checker_targets_div_by_zero_bmc/input.sol:9:3:
|
||||
|
|
||||
9 | 2 / x;
|
||||
| ^^^^^
|
||||
Note: Counterexample:
|
||||
<result> = 0
|
||||
a = 0
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -8,7 +8,7 @@ Transaction trace:
|
||||
test.constructor()
|
||||
State: arr = []
|
||||
test.f(0, 1)
|
||||
--> model_checker_targets_div_by_zero_chc/input.sol:10:3:
|
||||
|
|
||||
10 | 2 / x;
|
||||
| ^^^^^
|
||||
--> model_checker_targets_div_by_zero_chc/input.sol:9:3:
|
||||
|
|
||||
9 | 2 / x;
|
||||
| ^^^^^
|
||||
|
@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
pragma experimental SMTChecker;
|
||||
contract test {
|
||||
uint[] arr;
|
||||
function f(address payable a, uint x) public {
|
||||
|
@ -1 +1 @@
|
||||
--model-checker-targets aaa,bbb
|
||||
--model-checker-engine all --model-checker-targets aaa,bbb
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user