Solidity Needs Consistent Semantics

For a language that is mission critical and is relied upon to secure billions of $ in assets it seems self evident to me that there should not be subtle semantic changes caused by a simple compiler optimization flag being turned on: Solidity IR-based Codegen Changes — Solidity 0.8.31 documentation

While I understand that under the hood much more is going on than simply “optimizing the code” when you turn on --via-ir it seems that it’s crucial to not introduce more footguns than necessary into the language.

If the language feature is niche / hard to recreate the behavior of shouldn’t it just be deprecated and removed instead? Isn’t a seemingly backwards compatible but actually not implementation the worst of both worlds?

As a smart contract developer & auditor I judge it to be easier to update code that relies on removed features rather than have to think about & engineer around the possible behaviors of the language under the two modes.

What can be done to avoid this kind of thing in the future?

2 Likes

--via-ir is not an optimization flag. It switches the whole code generation backend. It’s orthogonal to whether the code is being optimized or not. It may be better to think about it as a whole new compiler than just a parameter change in the old one.

The plan is exactly to deprecate and remove the old backend. If everything went as planned the switch would have been quick and the semantic changes a non-issue. We routinely ship semantic changes in breaking versions and the switch between backends is such a change as well. Switch to --via-ir is not something that can ship quietly in 0.8.x either.

Unfortunately the work on the new backend took longer than expected and we ended up in a situation where both exist side by side for a significant period of time. Still, the expectation is for projects to migrate to IR once they feel it’s good enough for them, not stay compatible with both indefinitely.

As for what can be done, we could theoretically backport some of the changes to the legacy backend in 0.9.0 to make the backends closer in behavior and ease the transition. Perhaps for some changes this should have been done already in the past instead of putting them only in the new backend. For example, I suspect that doing this with the initialization order would be feasible. The problem is that not all changes are of this kind. Especially the new parameter evaluation order is intimately tied to the implementation and backporting it would be a lot of effort for little gain and a lot of risk or introducing subtle bugs. There’s a reason why writing code that depends on evaluation order is generally considered a bad practice. Such backporting would also have an impact on the general timeline and work on the IR backend.

Overall, I feel there’s not that much we can do right now other than just power through it. Our current work on the SSA CFG is pretty advanced by now and IR by default is not far off. We know it’s frustating to users and auditors and we feel that frustration as well, but the problem will ultimately be solved with time.

Theres currently no semantics. No semantic is better than any other. Using the word no but just different. Ok. Language like this is dangerous.

how? how do you always have to do it like this in controlled environments? lemme hang you from the wall street by your lips. cha ching. how?

This reply is not very constructive. What are you trying to say? Please contribute to the discussion in a meaningful way.

1 Like

Most developers using solidity would be very surprised that compiling with --via-ir can result in quite different code behavior when compiling identical solidity code. There is a long page in the Solidity compiler with a list of identical-code-different-behavior differences when compiling, as well as internal differences. And that page is not a complete list of the identical-code-different-behavior differences.

As Philology said, I believe it is not good that the Solidity language (as opposed to compiler) does not have a single behavior specification.

This is a minefield for developers and for auditors. It also makes secure compiler development more difficult because differential testing should be a powerful tool for correctness, but with intentional behavior differences between compilers, this is no longer simple.

It feels like Solidity should be a fully specified language, and any official solidity compilers should match that standard. If one version is the correct intended behavior, then both official solidity compilers should match that.

(Internal bytecode differences between compilers are fine, great, and expected. And if you monkey around with assembly, that’s between you and the compiler you use.)

The current Solidity plan is to switch to --via-ir compiling as the default compiling engine for 0.9?

At that point would non-ir compilation still be officially supported? Would it be deprecated and not recommended? Or would it be removed?

1 Like