Products
GG网络技术分享 2026-04-15 23:01 2
哎呀,这篇文章啊,写得跟打翻的咖啡一样乱七八糟,却偏偏想让搜索引擎爱上它。先别管逻辑, 先来点情绪:Solidity 编译器就像是那只总爱在凌晨吱吱叫的猫,你永远不知道它什么时候会把你家的灯泡给咬坏,实不相瞒...。
拭目以待。 别慌, 下面我们要聊的,就是那些编译器自带的“防御特性”,以及它们怎么帮我们躲避那些低级漏洞——比如说重入攻击整数溢出还有让人抓狂的selfdestruct呃。

从 solc 0.8.x 开始,编译器已经默认打开了很多“平安阀”。这些阀门有时像是老妈子一样唠叨, 有时又像是闹钟一样吓人:
+, -, *, / 前面加了个“检测”溢出直接抛异常。public/external? 编译器会狂喊 “Missing visibility!”。注意!以下示例仅作演示,请勿直接复制到生产环境!否则后果自负,一阵见血。。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract BadBank {
mapping public bal;
function deposit external payable { bal += msg.value; }
function withdraw external {
require;
= msg.sender.call{value:amount};
require;
bal -= amount; // ← 这里顺序错位,被攻击者利用
}
}
防御手段:
nonReentrant 修饰符。uint256 public totalSupply = type.max;
function mint external {
totalSupply += amount; // 编译期自动检查, 若溢出会 revert
}
的合约突然拥有余额)
contract Victim {
uint256 public balance;
}
contract Attacker {
function attack external payable {
selfdestruct; // 强行把 ETH 推进去
}
}
冲鸭! EIP-1822和 Transparent Proxy 常常被误用,引发槽冲突。下面这段代码就是典型案例:
| # | Name | Description | Status |
|---|---|---|---|
| 1 | LegoProxyV1.sol | A simple proxy with slot 0 = admin, slot 1 = implementation. | ✅ 平安 |
| 2 | LegoProxyV2_Bad.sol | Mistakenly added a new state variable at slot 0 causing admin 被覆盖. | ❌ 凶险 |
| 3 | LegoProxyV3_Fixed.sol | Adds __gap before new vars to keep alignment.✅ 平安 | |
| * 表格仅为演示目的,并非真实产品信息。 | |||
看表格,你会发现"__gap" 是解决槽冲突最常见也最实用的方法。它本质上是预留了 N 个空位, 没法说。 让以后升级时有空间放新变量而不覆盖旧数据。
EIP-165 定义了接口 ID,而 Solidity 则把函数签名哈希后取前四字节做选择器。按道理讲两条不同函数可能产生相同选择器, 这叫"selector collision". 虽然概率极低 ),但已经有人实战利用过:,翻旧账。
// 两个不同签名却同选
// selector")) == selector"))
function foo external {}
function bar external {}
// 调用时如果传错参数,就可能施行意外逻辑
防御技巧:使用 OpenZeppelin 的 @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol, 并在部署前通过工具(如 Solc-select / erscan's verify tool ) 检查选择器唯一性,你想...。
-vvv --match-path test/SlotCollisionTest.sol .总的 Solidity 编译器已经帮我们挡住了不少低级坑,但真正想要平安,还得靠开发者自己动手去补齐细节。记住:
@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol .
Demand feedback