0
string test;
    function assemblyStorage() public payable returns (string memory a){
     test = "good";
     assembly {
         a:=sload(0)
     }
    }

I am trying to return the string which should be stored in the first slot alongside the length of the string as stated in the docs. But calling assemblyStorage function results : increase gas limit . Whatever I increase it too, it doesn't matter. What Really causes this error is the assembly code. no idea why.

  • It's not the contract asking that, it's your transaction execution, whose code you haven't provided here. – goodvibration Oct 2 at 17:23
  • calling from remix. no need to provide any code since there are not any – Nika Kurashvili Oct 2 at 17:28
  • You're missing view, to begin with. This makes your RPC into a transaction, which requires mining, and whose return-value is not visible off-chain (e.g., in remix). Second, you are attempting to write an integer into a string. Not so sure about the meaning of that in Solidity. The equivalent of that in C would be (yet again, when considering all your recent questions) undefined behavior. It's a little pointless to try and explain the result of UB code. – goodvibration Oct 2 at 17:34
  • how am I trying to write an integer into a string ? – Nika Kurashvili Oct 2 at 17:57
  • a:=sload(0)... – goodvibration Oct 2 at 18:26
1

The problem is that a ends up pointing to a very large memory address and that causes the EVM to run out of gas, since you need to pay for memory used.

The first storage slot was modified by this line

test = "good";

Since it is a "short" string (less than 31 bytes) it is stored in one slot in compact form (data at the right and length x 2 at the left).

0x676f6f6400000000000000000000000000000000000000000000000000000008

For more detail read the article Diving Into The Ethereum VM Part 3 — The Hidden Costs of Arrays.

Then a is overwritten with the content of the first storage slot.

a := sload(0)

Now a is pointing to a very large address and that causes the out of gas error because solidity tries to read from it, and you need to pay gas for whole memory even if it wasn't assigned anything.


We can do safely for "short" string in assembly with

function assemblyStorage() public payable returns (string memory a){
    test = "good";
    assembly {
        let r := sload(0)
        // string length
        let l := shr(1, and(r, 0xff))
        // allocate memory for a
        a := mload(0x40)
        // update free memory pointer
        // a + 0x20 + 0x20 * trunc((l + 0x1f) / 0x20)
        mstore(0x40, add(a, add(0x20, shl(5, shr(5, add(l, 0x1f))))))
        // store length
        mstore(a, l)
        // copy data
        mstore(add(a, 0x20), and(r, not(0xff)))
    }
}

In this case using solidity directly is much easier and less error prone. It will work for any string.

function assemblyStorage() public payable returns (string memory a){
    test = "good";
    a = test;
}
| improve this answer | |
  • Thanks for the very helpful answer. one note though, from your example: a:=sload(0) means that a would get equal to 0x676f6f6400000000000000000000000000000000000000000000000000000008. why doesn't the function then return 0x676f6f6400000000000000000000000000000000000000000000000000000008 as string ? – Nika Kurashvili Oct 3 at 23:01
  • @NikaKurashvili In assembly a is a pointer you aren't modifying a's content but its address. It fails when solidity tries to read from the pointer. – Ismael Oct 3 at 23:16
  • so in a nutshell, a is an address. if so, why doesn't it return address as a string ? it seems like after assembly, solidity tries to load from that address again. it's like load(sload(0)) where load function just loads data from sload(0) . makes sense ? – Nika Kurashvili Oct 3 at 23:30
  • @NikaKurashvili I didn't read the compiler source, I'd guess it is a sort of function epilogue, perhaps it is trying to copy all return data to one buffer the it will use for the RETURN opcode. Let's say the compiler is not very smart. – Ismael Oct 3 at 23:51
  • This still doesn't make sense to me. 0th slot contains 0x676f6f6400000000000000000000000000000000000000000000000000000008. I think when we do this sload(0), solidity can't get the actual string , since it contains integer+string. and hence the error . don't you think ? – Nika Kurashvili Oct 4 at 0:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.