1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
/*
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/>.
*/
/**
* @file KnownState.h
* @author Christian <c@ethdev.com>
* @date 2015
* Contains knowledge about the state of the virtual machine at a specific instruction.
*/
#pragma once
#include <vector>
#include <map>
#include <set>
#include <tuple>
#include <memory>
#include <ostream>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wredeclared-class-member"
#endif // defined(__clang__)
#include <boost/bimap.hpp>
#if defined(__clang__)
#pragma clang diagnostic pop
#endif // defined(__clang__)
#include <libdevcore/CommonIO.h>
#include <libdevcore/Exceptions.h>
#include <libevmasm/ExpressionClasses.h>
#include <libevmasm/SemanticInformation.h>
namespace langutil
{
struct SourceLocation;
}
namespace dev
{
namespace eth
{
class AssemblyItem;
using AssemblyItems = std::vector<AssemblyItem>;
/**
* Class to infer and store knowledge about the state of the virtual machine at a specific
* instruction.
*
* The general workings are that for each assembly item that is fed, an equivalence class is
* derived from the operation and the equivalence class of its arguments. DUPi, SWAPi and some
* arithmetic instructions are used to infer equivalences while these classes are determined.
*/
class KnownState
{
public:
using Id = ExpressionClasses::Id;
struct StoreOperation
{
enum Target { Invalid, Memory, Storage };
StoreOperation(): target(Invalid), sequenceNumber(-1) {}
StoreOperation(
Target _target,
Id _slot,
unsigned _sequenceNumber,
Id _expression
): target(_target), slot(_slot), sequenceNumber(_sequenceNumber), expression(_expression) {}
bool isValid() const { return target != Invalid; }
Target target;
Id slot;
unsigned sequenceNumber;
Id expression;
};
explicit KnownState(
std::shared_ptr<ExpressionClasses> _expressionClasses = std::make_shared<ExpressionClasses>()
): m_expressionClasses(_expressionClasses)
{
}
/// Streams debugging information to @a _out.
std::ostream& stream(std::ostream& _out) const;
/// Feeds the item into the system for analysis.
/// @returns a possible store operation
StoreOperation feedItem(AssemblyItem const& _item, bool _copyItem = false);
/// Resets any knowledge about storage.
void resetStorage() { m_storageContent.clear(); }
/// Resets any knowledge about storage.
void resetMemory() { m_memoryContent.clear(); }
/// Resets any knowledge about the current stack.
void resetStack() { m_stackElements.clear(); m_stackHeight = 0; }
/// Resets any knowledge.
void reset() { resetStorage(); resetMemory(); resetStack(); }
unsigned sequenceNumber() const { return m_sequenceNumber; }
/// Replaces the state by the intersection with _other, i.e. only equal knowledge is retained.
/// If the stack heighht is different, the smaller one is used and the stack is compared
/// relatively.
/// @param _combineSequenceNumbers if true, sets the sequence number to the maximum of both
void reduceToCommonKnowledge(KnownState const& _other, bool _combineSequenceNumbers);
/// @returns a shared pointer to a copy of this state.
std::shared_ptr<KnownState> copy() const { return std::make_shared<KnownState>(*this); }
/// @returns true if the knowledge about the state of both objects is (known to be) equal.
bool operator==(KnownState const& _other) const;
/// Retrieves the current equivalence class fo the given stack element (or generates a new
/// one if it does not exist yet).
Id stackElement(int _stackHeight, langutil::SourceLocation const& _location);
/// @returns the stackElement relative to the current stack height.
Id relativeStackElement(int _stackOffset, langutil::SourceLocation const& _location = {});
/// @returns its set of tags if the given expression class is a known tag union; returns a set
/// containing the tag if it is a PushTag expression and the empty set otherwise.
std::set<u256> tagsInExpression(Id _expressionId);
/// During analysis, different tags on the stack are partially treated as the same class.
/// This removes such classes not to confuse later analyzers.
void clearTagUnions();
int stackHeight() const { return m_stackHeight; }
std::map<int, Id> const& stackElements() const { return m_stackElements; }
ExpressionClasses& expressionClasses() const { return *m_expressionClasses; }
std::map<Id, Id> const& storageContent() const { return m_storageContent; }
private:
/// Assigns a new equivalence class to the next sequence number of the given stack element.
void setStackElement(int _stackHeight, Id _class);
/// Swaps the given stack elements in their next sequence number.
void swapStackElements(int _stackHeightA, int _stackHeightB, langutil::SourceLocation const& _location);
/// Increments the sequence number, deletes all storage information that might be overwritten
/// and stores the new value at the given slot.
/// @returns the store operation, which might be invalid if storage was not modified
StoreOperation storeInStorage(Id _slot, Id _value, langutil::SourceLocation const& _location);
/// Retrieves the current value at the given slot in storage or creates a new special sload class.
Id loadFromStorage(Id _slot, langutil::SourceLocation const& _location);
/// Increments the sequence number, deletes all memory information that might be overwritten
/// and stores the new value at the given slot.
/// @returns the store operation, which might be invalid if memory was not modified
StoreOperation storeInMemory(Id _slot, Id _value, langutil::SourceLocation const& _location);
/// Retrieves the current value at the given slot in memory or creates a new special mload class.
Id loadFromMemory(Id _slot, langutil::SourceLocation const& _location);
/// Finds or creates a new expression that applies the Keccak-256 hash function to the contents in memory.
Id applyKeccak256(Id _start, Id _length, langutil::SourceLocation const& _location);
/// @returns a new or already used Id representing the given set of tags.
Id tagUnion(std::set<u256> _tags);
/// Current stack height, can be negative.
int m_stackHeight = 0;
/// Current stack layout, mapping stack height -> equivalence class
std::map<int, Id> m_stackElements;
/// Current sequence number, this is incremented with each modification to storage or memory.
unsigned m_sequenceNumber = 1;
/// Knowledge about storage content.
std::map<Id, Id> m_storageContent;
/// Knowledge about memory content. Keys are memory addresses, note that the values overlap
/// and are not contained here if they are not completely known.
std::map<Id, Id> m_memoryContent;
/// Keeps record of all Keccak-256 hashes that are computed.
std::map<std::vector<Id>, Id> m_knownKeccak256Hashes;
/// Structure containing the classes of equivalent expressions.
std::shared_ptr<ExpressionClasses> m_expressionClasses;
/// Container for unions of tags stored on the stack.
boost::bimap<Id, std::set<u256>> m_tagUnions;
};
}
}
|