diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/common-patterns.rst | 1 | ||||
-rw-r--r-- | docs/conf.py | 2 | ||||
-rw-r--r-- | docs/control-structures.rst | 4 | ||||
-rw-r--r-- | docs/miscellaneous.rst | 55 | ||||
-rw-r--r-- | docs/security-considerations.rst | 45 |
5 files changed, 102 insertions, 5 deletions
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 9096571e..422e2758 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -201,6 +201,7 @@ function finishes. now >= creationTime + 12 days) nextStage(); // The other stages transition by transaction + _ } // Order of the modifiers matters here! diff --git a/docs/conf.py b/docs/conf.py index 8776ec43..d0e26362 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -49,7 +49,7 @@ master_doc = 'index' # General information about the project. project = 'Solidity' -copyright = '2015, Ethereum' +copyright = '2016, Ethereum' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 064996ac..f30a5bdd 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -422,7 +422,7 @@ The opcodes ``pushi`` and ``jumpdest`` cannot be used directly. +-------------------------+------+-----------------------------------------------------------------+ | dup1 ... dup16 | | copy ith stack slot to the top (counting from top) | +-------------------------+------+-----------------------------------------------------------------+ -| swap1 ... swap1 | `*` | swap topmost and ith stack slot below it | +| swap1 ... swap16 | `*` | swap topmost and ith stack slot below it | +-------------------------+------+-----------------------------------------------------------------+ | mload(p) | | mem[p..(p+32)) | +-------------------------+------+-----------------------------------------------------------------+ @@ -661,7 +661,7 @@ variables. Take care that when you assign to variables that point to memory or storage, you will only change the pointer and not the data. There are two kinds of assignments: Functional-style and instruction-style. -For functionaly-style assignments (``variable := value``), you need to provide a value in a +For functional-style assignments (``variable := value``), you need to provide a value in a functional-style expression that results in exactly one stack value and for instruction-style (``=: variable``), the value is just taken from the stack top. For both ways, the colon points to the name of the variable. diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index 85fc286c..9b067fb1 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -95,6 +95,59 @@ is simplified to code which can also be compiled from even though the instructions contained a jump in the beginning. +.. index:: source mappings + +*************** +Source Mappings +*************** + +As part of the AST output, the compiler provides the range of the source +code that is represented by the respective node in the AST. This can be +used for various purposes ranging from static analysis tools that report +errors based on the AST and debugging tools that highlight local variables +and their uses. + +Furthermore, the compiler can also generate a mapping from the bytecode +to the range in the source code that generated the instruction. This is again +important for static analysis tools that operate on bytecode level and +for displaying the current position in the source code inside a debugger +or for breakpoint handling. + +Both kinds of source mappings use integer indentifiers to refer to source files. +These are regular array indices into a list of source files usually called +``"sourceList"``, which is part of the combined-json and the output of +the json / npm compiler. + +The source mappings inside the AST use the following +notation: + +``s:l:f`` + +Where ``s`` is the byte-offset to the start of the range in the source file, +``l`` is the length of the source range in bytes and ``f`` is the source +index mentioned above. + +The encoding in the source mapping for the bytecode is more complicated: +It is a list of ``s:l:f:j`` separated by ``;``. Each of these +elements corresponds to an instruction, i.e. you cannot use the byte offset +but have to use the instruction offset or PC (program counter). +The fields ``s``, ``l`` and ``f`` are as above and ``j`` can be either +``i``, ``o`` or ``-`` signifying whether a jump instruction goes into a +function, returns from a function or is a regular jump as part of e.g. a loop. + +In order to compress these source mappings especially for bytecode, the +following rules are used: + + - If a field is empty, the value of the preceding element is used. + - If a ``:`` is missing, all following fields are considered empty. + +This means the following source mappings represent the same information: + +``1:2:1;1:9:1;2:1:2;2:1:2;2:1:2`` + +``1:2:1;:9;2::2;;`` + + .. index:: ! commandline compiler, compiler;commandline, ! solc, ! linker .. _commandline-compiler: @@ -192,7 +245,7 @@ Function Visibility Specifiers - ``public``: visible externally and internally (creates accessor function for storage/state variables) - ``private``: only visible in the current contract -- ``external``: only visible externally (only for functions) - i.e. can only be message-called (via ``this.fun``) +- ``external``: only visible externally (only for functions) - i.e. can only be message-called (via ``this.func``) - ``internal``: only visible internally diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index f1a5dc03..bae6e20b 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -138,6 +138,45 @@ Note that ``.send()`` does **not** throw an exception if the call stack is depleted but rather returns ``false`` in that case. The low-level functions ``.call()``, ``.callcode()`` and ``.delegatecall()`` behave in the same way. +tx.origin +========= + +Never use tx.origin for authorization. Let's say you have a wallet contract like this: + +:: + + contract TxUserWallet { + address owner; + + function TxUserWallet() { + owner = msg.sender; + } + + function transfer(address dest, uint amount) { + if (tx.origin != owner) { throw; } + if (!dest.call.value(amount)()) throw; + } + } + +Now someone tricks you into sending ether to the address of this attack wallet: + +:: + + contract TxAttackWallet { + address owner; + + function TxAttackWallet() { + owner = msg.sender; + } + + function() { + TxUserWallet(msg.sender).transfer(owner, msg.sender.balance); + } + } + +If your wallet had checked msg.sender for authorization, it would get the address of the attack wallet, instead of the owner address. But by checking tx.origin, it gets the original address that kicked off the transaction, which is still the owner address. The attack wallet instantly drains all your funds. + + Minor Details ============= @@ -146,7 +185,11 @@ Minor Details Furthermore, it is not enforced by the EVM, so a contract function that "claims" to be constant might still cause changes to the state. - Types that do not occupy the full 32 bytes might contain "dirty higher order bits". - This is especially important if you access ``msg.data`` - it poses a malleability risk. + This is especially important if you access ``msg.data`` - it poses a malleability risk: + You can craft transactions that call a function ``f(uint8 x)`` with a raw byte argument + of ``0xff000001`` and with ``0x00000001``. Both are fed to the contract and both will + look like the number ``1`` as far as ``x`` is concerned, but ``msg.data`` will + be different, so if you use ``sha3(msg.data)`` for anything, you will get different results. *************** Recommendations |