@@ -228,6 +228,11 @@ of their block is reached.
228
228
Conventions in Solidity
229
229
-----------------------
230
230
231
+ .. _assembly-typed-variables :
232
+
233
+ Values of Typed Variables
234
+ =========================
235
+
231
236
In contrast to EVM assembly, Solidity has types which are narrower than 256 bits,
232
237
e.g. ``uint24 ``. For efficiency, most arithmetic operations ignore the fact that
233
238
types can be shorter than 256
@@ -237,6 +242,11 @@ This means that if you access such a variable
237
242
from within inline assembly, you might have to manually clean the higher-order bits
238
243
first.
239
244
245
+ .. _assembly-memory-management :
246
+
247
+ Memory Management
248
+ =================
249
+
240
250
Solidity manages memory in the following way. There is a "free memory pointer"
241
251
at position ``0x40 `` in memory. If you want to allocate memory, use the memory
242
252
starting from where this pointer points at and update it.
@@ -268,3 +278,89 @@ first slot of the array and followed by the array elements.
268
278
Statically-sized memory arrays do not have a length field, but it might be added later
269
279
to allow better convertibility between statically- and dynamically-sized arrays, so
270
280
do not rely on this.
281
+
282
+ Memory Safety
283
+ =============
284
+
285
+ Without the use of inline assembly, the compiler can rely on memory to remain in a well-defined
286
+ state at all times. This is especially relevant for :ref: `the new code generation pipeline via Yul IR <ir-breaking-changes >`:
287
+ this code generation path can move local variables from stack to memory to avoid stack-too-deep errors and
288
+ perform additional memory optimizations, if it can rely on certain assumptions about memory use.
289
+
290
+ While we recommend to always respect Solidity's memory model, inline assembly allows you to use memory
291
+ in an incompatible way. Therefore, moving stack variables to memory and additional memory optimizations are,
292
+ by default, disabled in the presence of any inline assembly block that contains a memory operation or assigns
293
+ to solidity variables in memory.
294
+
295
+ However, you can specifically annotate an assembly block to indicate that it in fact respects Solidity's memory
296
+ model as follows:
297
+
298
+ .. code-block :: solidity
299
+
300
+ /// @solidity memory-safe-assembly
301
+ assembly {
302
+ ...
303
+ }
304
+
305
+ In particular, a memory-safe assembly block may only access the following memory ranges:
306
+
307
+ - Memory allocated by yourself using a mechanism like the ``allocate `` function described above.
308
+ - Memory allocated by Solidity, e.g. memory within the bounds of a memory array you reference.
309
+ - The scratch space between memory offset 0 and 64 mentioned above.
310
+ - Temporary memory that is located *after * the value of the free memory pointer at the beginning of the assembly block,
311
+ i.e. memory that is "allocated" at the free memory pointer without updating the free memory pointer.
312
+
313
+ Furthermore, if the assembly block assigns to Solidity variables in memory, you need to assure that accesses to
314
+ the Solidity variables only access these memory ranges.
315
+
316
+ Since this is mainly about the optimizer, these restrictions still need to be followed, even if the assembly block
317
+ reverts or terminates. As an example, the following assembly snippet is not memory safe:
318
+
319
+ .. code-block :: solidity
320
+
321
+ assembly {
322
+ returndatacopy(0, 0, returndatasize())
323
+ revert(0, returndatasize())
324
+ }
325
+
326
+ But the following is:
327
+
328
+ .. code-block :: solidity
329
+
330
+ /// @solidity memory-safe-assembly
331
+ assembly {
332
+ let p := mload(0x40)
333
+ returndatacopy(p, 0, returndatasize())
334
+ revert(p, returndatasize())
335
+ }
336
+
337
+ Note that you do not need to update the free memory pointer if there is no following allocation,
338
+ but you can only use memory starting from the current offset given by the free memory pointer.
339
+
340
+ If the memory operations use a length of zero, it is also fine to just use any offset (not only if it falls into the scratch space):
341
+
342
+ .. code-block :: solidity
343
+
344
+ /// @solidity memory-safe-assembly
345
+ assembly {
346
+ revert(0, 0)
347
+ }
348
+
349
+ Note that not only memory operations in inline assembly itself can be memory-unsafe, but also assignments to
350
+ solidity variables of reference type in memory. For example the following is not memory-safe:
351
+
352
+ .. code-block :: solidity
353
+
354
+ bytes memory x;
355
+ assembly {
356
+ x := 0x40
357
+ }
358
+ x[0x20] = 0x42;
359
+
360
+ Inline assembly that neither involves any operations that access memory nor assigns to any solidity variables
361
+ in memory is automatically considered memory-safe and does not need to be annotated.
362
+
363
+ .. warning ::
364
+ It is your responsibility to make sure that the assembly actually satisfies the memory model. If you annotate
365
+ an assembly block as memory-safe, but violate one of the memory assumptions, this **will ** lead to incorrect and
366
+ undefined behaviour that cannot easily be discovered by testing.
0 commit comments