区块链 智能合约安全 | 整型溢出漏洞
目录:
核心概念
溢出类型
上溢
原理
案例
下溢
原理
案例
练习
漏洞修复
使用 SafeMath 库(旧版本)
升级 Solidity 版本(≥0.8.0)
地址:zkanzz
整型溢出漏洞(Integer Overflow/Underflow Vulnerability)是计算机程序中因数值运算超出数据类型范围而导致的异常行为。可能导致的危害: 在智能合约中,这种漏洞可能导致资产计算错误、权限绕过, 合约逻辑失控,是区块链安全领域的高危风险之一。
在Solidity中, 当我们定义一个整型数据类型时通常需要声明这个整型的长度,在学习Solidity的过程中, 我们学习到整型有无符号整型uint与整型int类型 ,如果直接使用uint声明
uint a; // 这里等效于声明 uint256 a
核心概念
数据类型的有限性 ,计算机中所有数值类型都有固定的存储空间(例如 uint256 用 256 位二进制存储),其取值范围被严格限制
uint8:0 ~ 255(2的8次方-1)
int8:-128 ~ 127 (-1 * 2的7次方 到 2的7次方-1)
溢出类型
上溢(Overflow):数值超过类型最大值 下溢(Underflow):数值低于类型最小值
上溢
原理
下面我们用uint8举例,uint8就是使用了8个比特位,其值的范围是0-2的八次方,也就是 0 - 255,255是uint8数据类型可以存储的最大值,那么如果我们设置一个uint8变量等于255,对其加1会发生什么呢,测试代码如下
// SPDX-License-Identifier: GPL-3.0
pragma solidity = 0.7.6;
contract Test {
function test() public pure returns(uint8) {
uint8 a = 255;
return a + 1;
}
}
运行可以看到如下结果, 最后的值是0
其中运算过程是怎样的呢?
当我们定义了uint8 a = 255 之后,系统为我们分配了一个大小为8bit的内存空间,随后设置其值为255, 换成2进制也就是 1111 1111(为了方便查看这里加上空格),不论是传统的系统还是区块链网络,其底层都是2进制,当我们执行a+1时,也就是二进制的 1111 1111 + 1
最后结果是
1 0000 0000
因为存储结果的变量只有 8 bit,最高位的1会被丢弃,最后只剩下
0000 0000
换算回10进制也就是0
同理, 如果是+2,那么就是
1 0000 0001
最高位被丢弃, 结果值为1
这就是整型上溢,上溢会使得原本很大的值变得很小
案例
假设我们有一个区块链网店业务,示例代码如下, 这种代码理论上是要用 uint256 的, 但是这里为了方便理解我将uint256都修改为了uint8, 实际利用中只需要增加对应的值使其超过2^256-1即可
这里当我们购买128个商品1时就会触发漏洞
// SPDX-License-Identifier: MIT
pragma solidity = 0.7.6;
contract OnlineStore {
// 商品结构体
struct Product {
uint256 id;
string name;
uint8 price; // 单位 eth
}
// 商品存储不定长数组
Product[] private products;
// 初始化函数
constructor() {
// 创建三个示例商品
products.push(Product(1, "Phone", 2)); // 1 ETH
products.push(Product(2, "Laptop", 3)); // 3 ETH
products.push(Product(3, "Headphones", 1)); // 0.5 ETH
}
// 价格计算函数
function calculatePrice(uint8 _productId, uint8 _quantity)
public
view
returns (uint8)
{
Product memory product = getProductById(_productId);
require(product.id != 0, "Product not found");
require(_quantity > 0, "Quantity must be greater than 0");
return product.price * _quantity;
}
// 购买函数
function purchase(uint8 _productId, uint8 _quantity) public payable returns(string memory){
uint8 totalPrice = calculatePrice(_productId, _quantity);
// 检查支付金额
require(msg.value == totalPrice * 10 ** 18, "Incorrect ETH amount");
return "success";
}
// 根据ID查询商品(内部函数)
function getProductById(uint256 _productId)
internal
view
returns (Product memory)
{
for (uint256 i = 0; i < products.length; i++) {
if (products[i].id == _productId) {
return products[i];
}
}
return Product(0, "", 0); // 返回空商品
}
function test(uint8 a) public pure returns(uint8) {
return a + 1;
}
}
接下来来看一下漏洞的产生过程 当我们输入了购买id 1 和购买数量128之后 会先从商品列表中找到对应的商品, 取出其价格 计算 totalPrice = 2 * 128 = 256 因为使用uint8存储 只有8位bit 256的2进制为 1 0000 0000 存储时最高位被丢弃 最后只剩下了 0000 0000
我们部署好代码后运行 大家也可以换成127, 129看看结果
在购买函数中执行 可以看到会返回对应的 success
大家可以自己把uint8改成uint256再测试 另外这里有一个问题 即购买商品3我们无法产生溢出 原因是我们把购买数量设置为了uint8 当我们输入大于255的数字时会直接报错输入类型不匹配, uint8装不下这么大的数字 这里其实可以把uint8改更大, 不影响结果 大家自己多试一试, 也能增加一些理解
下溢
原理
我们继续用uint8类型举例
uint8 a = 0;
return a-1;
这段代码的运行结果我们思考一下会是什么 这里需要一些二进制的基础 在计算机中,减法是通过补码(Two’s Complement)实现的。具体步骤如下:例如我们要计算2-1, -1的二进制表示就是1的补码 首先我们要计算 1 的补码:1 的二进制表示:0000 0001 1 的补码(取反加 1):首先进行取反 得到 1111 1110 加1得到 11111111 减法操作也就是加上对应数字的补码执行加法操作:2 的二进制表示是 0000 0010 那么 2 - 1就是 0000 0010 + 1111 1111 得到 1 0000 0001 去掉进位(就是比原本多出来的位数) 得到 0000 0001 也就是十进制的1
看的不是很明白? 我们再来一个案例 5-2 首先计算2的补码 取反: 1111 1101 加一得到: 1111 1110 5的二进制表示是: 0000 0101 0000 0101 + 1111 1110 = 1 0000 0011 或者换一种方法展示(记得从下往上看)
= 1(进位进上来的)
0 + 1 = 1 + 1 = 0
0 + 1 = 1 + 1 = 0
0 + 1 = 1 + 1 = 0
0 + 1 = 1+1 (同下, 也是进位, 后面不在赘述) = 0
0 + 1 = 1 + 1(这个1是进位) = 0 进一位
1 + 1 = 1 进一位
0 + 1 = 1
1 + 0 = 1
最后结果就是 1 0000 0011 去掉进位 得到 0000 0011 也就是2的0次方+2的1次方= 1+2 = 3
我们继续, 如果是0-1呢 8位bit下0的二进制表示 0000 0000 1的二进制表示 0000 0001 取反: 1111 1110 加一: 1111 1111 -1就是 1111 1111 0-1 -> 0000 0000 + 1111 1111 = 1111 1111 没有进位 最终值是256 拿uint8举例是8个bit表示一组 如果是uint16 那0就是 0000 0000 0000 0000 1就是 0000 0000 0000 0001 -1就是(同样是取反再加一) 1111 1111 1111 1111 0-1就是 0000 0000 0000 0000 + 1111 1111 1111 1111 最后得到 1111 1111 1111 1111 = 2的16次方 - 1 等于65535 大家可以在Solidity或者C语言中试验一下如下代码查看结果 这里就不再演示
uint16 a = 0;
return a-1;
大家也可以自行尝试计算uint16下的5 - 2的计算 这里就不再浪费篇幅
案例
整型下溢的案例比如说存款合约取款 大家可以先查看这段代码 尝试下是否能看出问题
contract Bank {
....
mapping(address => uint256) public balanceOf;
function withdraw(uint256 amount) public {
require(balanceOf[msg.sender] - amount >= 0);
balanceOf[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
}
这段代码乍看之下是没有问题的,但是我们要考虑到,balanceOf中存储的是uint256, 无符号整数,amount也是无符号整数,它们相减的结果也会是一个uint256无符号整数,如果balanceOf[msg.sender]的值是0,amout是1,无符号整数0-1得到的结果会发生下溢,就像我们刚刚说的,uint16下 0-1 会变成uint16能表示的最大值,这里就会变成uint256能表示的最大值, 2的256次方-1,这里得到的结果永远大于0,也就是说这段代码恒成立,可以任意取款
那么接下来实验一下, 结果是否如我们所想 上面的代码是不全的, 无法直接测试 我们先增加一个存款函数(不然合约没钱没法转出来) 测试代码如下
// SPDX-License-Identifier: MIT
pragma solidity = 0.7.6;
contract Bank {
mapping(address => uint256) public balanceOf;
function deposit() public payable { // Deposit Ether
}
function withdraw(uint256 amount) public payable {
require(balanceOf[msg.sender] - amount >= 0);
balanceOf[msg.sender] -= amount;
payable(msg.sender).transfer(amount);
}
}
我们这里没有写往balanceOf中增加数值的方法,不管msg.sender是什么, balanceOf[msg.sender]的值都是0,部署好之后
这里设置好发送的eth
然后调用deposit函数,往里面先存点eth方便测试,看到合约余额增加之后
我们在取款函数中填入500000(这里是用wei做单位),执行函数,可以看到发生了取款操作
你也可以写一个函数,用来查看balanceOf[msg.sender]是否是0,但当你取款过一次之后, balanceOf[msg.sender]就不是0了,因为balanceOf[msg.sender] -= amount;时会发生溢出,将balanceOf[msg.sender]的值变成一个非常大的数
练习
最后放一个漏洞代码, 大家可以先自己练习 记得调整编译器为 0.4.21
pragma solidity ^0.4.21;
contract TokenSaleChallenge {
mapping(address => uint256) public balanceOf; // 存款
uint256 constant PRICE_PER_TOKEN = 1 ether; // 单位
function TokenSaleChallenge(address _player) public payable {
require(msg.value == 1 ether); // 创建时 写入一个地址, 然后需要发送1 eth 存进来
}
function isComplete() public view returns (bool) {
return address(this).balance < 1 ether; // 返回此合约内的 eth 余额是否小于 1 eth
}
function buy(uint256 numTokens) public payable {
require(msg.value == numTokens * PRICE_PER_TOKEN); // 检查发送的eth 与标记发送的是否一致
balanceOf[msg.sender] += numTokens; // 加上对应的余额
}
function sell(uint256 numTokens) public {
require(balanceOf[msg.sender] >= numTokens); // 检查调用者的余额是否大于等于取款的余额
balanceOf[msg.sender] -= numTokens; // 记账
msg.sender.transfer(numTokens * PRICE_PER_TOKEN); //取款
}
}
漏洞主要发生在 buy 函数中 我们首先分析如果正常存入 正常想要存入 1eth 我们首先传入参数 numTokens = 1 同时传入 1 eth 这时候 msg.value = 1 eth PRICE_PER_TOKEN = 1eth 1 * 1eth = 1eth 余额值会增加 1, 向其中存入1eth
那么漏洞是如何触发的? 首先我们要明确, msg.value的值是以wei做单位的 1eth = 10的18次方 msg.value实际上是一个整型 当我们传入1eth实际上 msg.value=1000000000000000000 我们传入的代币数量会乘以10^18 那么如果我们购买2的256次方 // 10的18次方 + 1 个代币时 最后的numTokens * PRICE_PER_TOKEN的值就是
(2^256 // 10^18 + 1) * 10^18
(115792089237316195423570985008687907853269984665640564039457584007913129639936 // 1000000000000000000 + 1) * 1000000000000000000
= 115792089237316195423570985008687907853269984665640564039458000000000000000000
最后得到的值大于2的256次方 会产生上溢 溢出之后的结果就是 415992086870360064 也就是 msg.value == 415992086870360064 即可存入 6432893846517566412420610278260439325181665814757809113303199111550729424441(这个值是 2的256次方整除 10的18次方 + 1)个代币 一个代币等价于1eth 415992086870360064约等于0.4eth 也就是说花费了0.4eth就能得到6432893846517566412420610278260439325181665814757809113303199111550729424441 eth的存款 实验: 发送415992086870360064 wei
buy的参数填入 115792089237316195423570985008687907853269984665640564039458
执行后查询自己的余额 发现已经变成了115792089237316195423570985008687907853269984665640564039458
漏洞修复
使用 SafeMath 库(旧版本)
using SafeMath for uint8; // 对uint8类型检查是否产生溢出
balances[msg.sender] = balances[msg.sender].sub(_amount);
升级 Solidity 版本(≥0.8.0)
Solidity8.0版本新增了溢出回滚操作 如果产生溢出会自动回滚交易 另外, 在Solidity >= 0.8.0 时, 想要关闭溢出检查需要使用unchecked关键字, 示例代码
uint8 a = 255;
unchecked {
a += 1; // 允许溢出,结果归零
}
申明:本账号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关
相关文章:
区块链 智能合约安全 | 整型溢出漏洞
目录: 核心概念 溢出类型 上溢 原理 案例 下溢 原理 案例 练习 漏洞修复 使用 SafeMath 库(旧版本) 升级 Solidity 版本(≥0.8.0) 地址:zkanzz 整型溢出漏洞(Integer Overflow/Underflow Vulne…...
C# HTTP 文件上传、下载服务器
程序需要管理员权限,vs需要管理员打开 首次运行需要执行以下命令注册URL(管理员命令行) netsh advfirewall firewall add rule name"FileShare" dirin actionallow protocolTCP localport8000 ipconfig | findstr "IPv4&quo…...
IDEA导入jar包后提示无法解析jar包中的类,比如无法解析符号 ‘log4j‘
IDEA导入jar包后提示无法解析jar包中的类 问题描述解决方法 问题描述 IDEA导入jar包的Maven坐标后,使用jar中的类比如log4j,仍然提示比如无法解析符号 log4j。 解决方法 在添加了依赖和配置文件后,确保刷新你的IDE项目和任何缓存ÿ…...
C++前缀和
个人主页:[PingdiGuo_guo] 收录专栏:[C干货专栏] 大家好,今天我们来了解一下C的一个重要概念:前缀和 目录 1.什么是前缀和 2.前缀和的用法 1.前缀和的定义 2.预处理前缀和数组 3.查询区间和 4.数组中某个区间的和是否为特定…...
kafka压缩
最近有幸公司参与kafka消息压缩,背景是日志消息量比较大。kafka版本2.4.1 一、确认压缩算法 根据场景不同选择不同。如果是带宽敏感患者推荐高压缩比的zstd,如果是cpu敏感患者推荐lz4 lz4和zstd底层都使用的是lz77算法,具体实现逻辑不同&am…...
C 语 言 --- 扫 雷 游 戏(初 阶 版)
C 语 言 --- 扫 雷 游 戏 初 阶 版 代 码 全 貌 与 功 能 介 绍扫雷游戏的功能说明游 戏 效 果 展 示游 戏 代 码 详 解game.htest.cgame.c 总结 💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 C 语 言 💡个 人 主…...
黑鲨外设2025春季新品发布会:全球首款“冷暖双控”鼠标亮相!
据可靠消息称,电竞外设领域的创新引领者——黑鲨外设,正式官宣将于2025年3月28日17:00召开主题为“究极体验,竞在其中”春季新品发布会。据悉,此次新品发布会将于黑鲨游戏外设和黑鲨游戏手机官方平台同步直播,…...
SpringBoot-MVC配置类与 Controller 的扫描
文章目录 前言一、自动配置类位置二、自动配置类解析2.1 WebMvcAutoConfiguration2.1.1 EnableWebMvcConfiguration 2.2 DispatcherServletAutoConfiguration 三、RequestMapping 的扫描过程3.1 RequestMappingHandlerMapping#afterPropertiesSet3.2 RequestMappingHandlerMapp…...
Nexus L2 L3基本配置
接口基本配置 N7K上所有端口默认处于shutdown状态; N5K上所有端口默认处于no shutdown状态(所有端口都是switchport) 默认所有接口都是三层route模式, 只有当线卡不支持三层的时候, 接口才会处于二层switchport模式 show run all | in “system default” 创建SVI口需要提前打…...
asp.net 4.5在医院自助系统中使用DeepSeek帮助医生分析患者报告
环境: asp.net 4.5Visual Studio 2015本地已经部署deepseek-r1:1.5b 涉及技术 ASP.NET MVC框架用于构建Web应用程序。使用HttpWebRequest和HttpWebResponse进行HTTP请求和响应处理。JSON序列化和反序列化用于构造和解析数据。SSE(服务器发送事件…...
LCCI ESG 中英联合认证国际分析师适合的岗位
LCCI ESG中英联合认证国际分析师领域热门岗位大揭秘!🌍 大家好!今天我们来探讨LCCI ESG中英联合认证国际分析师领域的热门岗位,看看是否有适合你的选择。 1️⃣ LCCI ESG中英联合认证国际分析师报告专员:主要负责编制…...
AGI成立的条件
AGI(通用人工智能)的成立需满足多项核心条件,这些条件既涵盖技术能力层面的突破,也涉及伦理与认知维度的考量。 一、通用性与多任务处理能力 跨领域泛化能力 AGI需具备类似人类的通用性,能够灵活切换不同领域…...
论文阅读:2023 EMNLP SeqXGPT: Sentence-level AI-generated text detection
总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 SeqXGPT: Sentence-level AI-generated text detection https://aclanthology.org/2023.emnlp-main.73/ https://github.com/Jihuai-wpy/SeqXGPT https://www.doubao.com/…...
解决python配置文件类configparser.ConfigParser,插入、读取数据,自动转为小写的问题
配置类 [Section1] Key_AAA Value[Section2] AnotherKey Value默认情况下,ConfigParser会将ini配置文件中的KEY,转为小写。 重载后配置类: 继承类从configparser.ConfigParser改为configparser.RawConfigParser重载方法optionxform&#…...
超图神经网络的详细解析与python示例
扩展传统集合关系至超边结构,处理高阶交互问题。 有关人工智能的数学基础之逻辑、集合论和模糊理论:看我文章人工智能的数学基础之逻辑、集合论和模糊理论-CSDN博客 一、超图神经网络概述 超图神经网络(Hypergraph Neural Network࿰…...
机器视觉中图像的腐蚀和膨胀是什么意思?它能用来做什么?
腐蚀(Erosion)和膨胀(Dilation)是两种基本的形态学操作,通常用于二值图像(黑白图像)的处理。它们是形态学图像处理的基础,广泛应用于图像分割、边缘检测、噪声去除等任务。 1…...
破局 MySQL 死锁:深入理解锁机制与高效解决方案
死锁的原理 1. 什么是死锁? 当 多个事务 在并发执行时,每个事务都 持有其他事务需要的锁,同时又在 等待对方释放锁,导致所有事务都无法继续执行的状态,称为 死锁(Deadlock)。 2. 死锁的四个必要…...
机器学习——分类、回归、聚类、LASSO回归、Ridge回归(自用)
纠正自己的误区:机器学习是一个大范围,并不是一个小的方向,比如:线性回归预测、卷积神经网络和强化学都是机器学习算法在不同场景的应用。 机器学习最为关键的是要有数据,也就是数据集 名词解释:数据集中的…...
脚本语言 Lua
概念 Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译、运行。Lua脚本可以很容易地被C/C 代码调用,也可以反过来调用C/C的函数,这使得Lua在应用程序中可以被广泛应用。Lua并没有提供强大的库,它是不适合作为开发独立应…...
Spring相关面试题
目录 Spring中常用的注解有哪些 Spring Boot中RestController和Controller注解有什么区别? Spring的注解requestBody和responseBody的区别 说说Bean和componentscan的区别 简单介绍一下springboot Spring Boot有哪些常用的Starter依赖? 说说sprin…...
Python学习- 数据结构类型
一. list list_data [10, 20, 30]列表:是一个不限制类型,可增加,修改,删除的数据类型 可操作的方法:append,extend, pop,del ,insert append: 可向list最后一个位置添加一个元…...
Azure Delta Lake、Databricks和Event Hubs实现实时欺诈检测
设计Azure云架构方案实现Azure Delta Lake和Azure Databricks,结合 Azure Event Hubs/Kafka 摄入实时数据,通过 Delta Lake 实现 Exactly-Once 语义,实时欺诈检测(流数据写入 Delta Lake,批处理模型实时更新࿰…...
【从零开始学习计算机科学】软件测试(十)嵌入式系统测试、游戏开发与测试过程、移动应用软件测试 与 云应用软件测试
【从零开始学习计算机科学】软件测试(十)嵌入式系统测试、游戏开发与测试过程、移动应用软件测试 与 云应用软件测试 嵌入式系统测试测试策略及测试流程嵌入式软件测试问题及测试方法嵌入式软件的测试流程游戏开发与测试过程游戏开发与通用软件的开发过程区别游戏测试主要内容…...
C#零基础入门篇(18. 文件操作指南)
## 一、文件操作基础 在C#中,文件操作主要通过System.IO命名空间中的类来实现,例如File、FileStream、FileInfo等。 ## 二、常用文件操作方法 ### (一)文件读取 1. **使用File.ReadAllText方法读取文件内容为字符串** …...
深入探究 JVM 堆的垃圾回收机制(一)— 判活
垃圾回收分为两步:1)判定对象是否存活。2)将“消亡”的对象进行内存回收。 1 判定对象存活 可达性分析算法:通过一系列“GC Roots”对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,…...
SQL优化主要有哪些方式
对经常查询的区分度高的条件字段建立索引,也就是用在where条件里的字段。使用没有建立索引的非主键字段作为条件查询时,会进行全表扫描,因为这个字段的数据分步是不规律的,但是需要避免在频繁更新的字段上建立索引,因为…...
基于Spring Boot的公司资产网站的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
笔记本电脑关不了机是怎么回事 这有解决方法
在快节奏的现代生活中,笔记本电脑已成为我们工作、学习和娱乐的得力助手。在使用电脑的过程中,笔记本电脑突然关不了机了,怎么回事?下面驱动人生就来讲一讲笔记本电脑不能正常关机的解决方法,有需要的可以来看看。 一、…...
OSPF 协议详解:从概念原理到配置实践的全网互通实现
什么是OSPF OSPF(开放最短路径优先)是由IETF开发的基于链路状态的自治系统内部路由协议,用来代替存在一些问题的RIP协议。与距离矢量协议不同,链路状态路由协议关心网络中链路活接口的状态(包括UP、DOWN、IP地址、掩码…...
【C++】多态
目录 文章目录 前言 一、多态的概念 二、多态的定义及实现 三、重载/重写/隐藏的对比 四、纯虚函数和抽象类 五、多态的原理 总结 前言 本文主要讲述C中的多态,涉及的概念有虚函数、协变、纯虚函数、抽象类、虚表指针和虚函数表等。 一、多态的概念 多态分…...
CentOS 8 停止维护后通过 rpm 包手动安装 docker
根据 Docker官方文档 的指引,进入 Docker rpm 包下载的地址,根据自己系统的架构和具体版本选择对应的路径 这里使用 Index of linux/centos/7/x86_64/stable/ 版本,根据 docker 官方的给出的安装命令选择性的下载对应的 rpm 包 最终使用 yum …...
STT-MRAM CIM 赋能边缘 AI:高性能噪声鲁棒贝叶斯神经网络宏架构详解
引言 近年来,基于卷积神经网络(CNN)和视觉转换器(ViT)的存算一体(CIM)边缘AI设备因其低延迟、高能效、低成本等性能受到越来越广泛的关注。然而,当环境中存在噪声时(例如…...
Performance Hub Active Report
Performance Hub 是 Oracle Enterprise Manager Database Express (EM Express) 中的一项功能,可提供给定时间范围内所有性能数据的新整合视图。用户可以使用 Database Express 页面顶部的时间选择器选择时间范围,详细信息选项卡将…...
小白闯AI:Llama模型Lora中文微调实战
文章目录 0、缘起一、如何对大模型进行微调二、模型微调实战0、准备环境1、准备数据2、模型微调第一步、获取基础的预训练模型第二步:预处理数据集第三步:进行模型微调第四步:将微调后的模型保存到本地4、模型验证5、Ollama集成部署6、结果测试三、使用总结AI是什么?他应该…...
【数学建模】TOPSIS法简介及应用
文章目录 TOPSIS法的基本原理TOPSIS法的基本步骤TOPSIS法的应用总结 在 多目标决策分析中,我们常常需要在多个选择中找到一个最优解。 TOPSIS(Technique for Order Preference by Similarity to Ideal Solution)法是一个广泛应用的决策方法…...
优选算法训练篇08--力扣15.三数之和(难度中等)
目录 1.题目链接:15.三数之和 2.题目描述: 3.解法(排序双指针) 1.题目链接:15.三数之和 2.题目描述: 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &…...
【docker】--- 详解 WSL2 中的 Ubuntu 和 Docker Desktop 的区别和关系!
在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。【WSL 】--- Windows11 迁移 WSL 超详细指南 —— 给室友换一个宿舍! 开发环境一、引…...
RAG 架构地基工程-Retrieval 模块的系统设计分享
目录 一、知识注入的关键前奏——RAG 系统中的检索综述 (一)模块定位:连接语言模型与知识世界的桥梁 (二)核心任务:四大关键问题的协调解法 (三)系统特征:性能、精度…...
解决stm32引脚如果选择输入模式
1. 输入模式分类 STM32的GPIO输入模式主要分为以下四种: 浮空输入(Floating Input / Input Floating) 上拉输入(Input Pull-Up) 下拉输入(Input Pull-Down) 模拟输入(Analog Inp…...
Java 填充 PDF 模版
制作 PDF 模版 安装 OnlyOffice 从 OnlyOffice 官网下载 OnlyOffice Desktop,安装过程很简单,一路下一步即可。用 OnlyOffice 制作 PDF 模版(表单) 使用 OnlyOffice 表单设计器,制作表单,如下图 注意命名…...
Maven安装与环境配置
首先我们先介绍一些关于Maven的知识,如果着急直接看下面的安装教程。 目录 Maven介绍 Maven模型 Maven仓库 Maven安装 下载 安装步骤 Maven介绍 Apache Maven是一个项目管理和构建工具,它基于项目对象模型(Project Object Model , 简称: POM)的概念…...
鸿蒙HarmonyOS NEXT应用崩溃分析及修复
鸿蒙HarmonyOS NEXT应用崩溃分析及修复 如何保证应用的健壮性,其中一个指标就是看崩溃率,如何降低崩溃率,就需要知道存在哪些崩溃,然后对症下药,解决崩溃。那么鸿蒙应用中存在哪些崩溃类型呢?又改如何解决…...
基于PySide6的CATIA自动化工具开发实战——空几何体批量清理系统
一、功能概述 本工具通过PySide6构建用户界面,结合PyCATIA库实现CATIA V5的自动化操作,提供两大核心功能: 空几何体清理:智能识别并删除零件文档中的无内容几何体(Bodies)空几何图形集清理࿱…...
【CSS文字渐变动画】
CSS文字渐变动画 HTML代码CSS代码效果图 HTML代码 <div class"title"><h1>今天是春分</h1><p>正是春天到来的日子,花都开了,小鸟也飞回来了,大山也绿了起来,空气也有点嫩嫩的气息了</p>…...
Mysql深分页的解决方案
在数据量非常大的情况下,深分页查询则变得很常见,深分页会导致MySQL需要扫描大量前面的数据,从而效率低下。例如,使用LIMIT 100000, 10时,MySQL需要扫描前100000条数据才能找到第10000页的数据。 在MySQL中解决深分页…...
使用pycel将Excel移植到Python
1.适用需求 有些工作可能长期适用excel来进行公式计算,当需要把工作流程转换为可视化界面时,开发人员不懂专业逻辑,手动摸索公式很大可能出错,而且费时费力 2.可用工具及缺点 pandas 方便进行数据处理,支持各种格…...
Apache Tomcat CVE-2025-24813 安全漏洞
Apache Tomcat CVE-2025-24813被广泛利用,但是他必须要满足两个点: 1.被广泛的使用,并且部署在服务器中。 2.漏洞必须依赖在服务器中的配置。 并且漏洞补丁已经发布。 漏洞攻击方式: CVE-2025-24813 是 Apache Tomcat 部分 PUT…...
Spring常用注解汇总
1. IOC容器与Bean管理 注解说明示例Component通用注解,标记类为Spring Bean Component public class MyService { ... } Controller标记Web控制器(应用在MVC的控制层) Controller public class UserController { ... } Service标记业务逻辑层…...
【CXX-Qt】2.1.1 为 WebAssembly 构建
CXX-Qt 及其编写的应用程序可以编译为 WebAssembly,但存在一些限制。以下是关于如何为 WASM 目标构建的详细说明。 你需要安装 Qt for WebAssembly。下一篇将展示已测试的版本。 此外,如果尚未完成,请从此处克隆 emsdk git 仓库。 使用正确…...
MySql创建分区表并且按月分区
前言 在mysql中,按月份分区,再使用分区字段时间来查询数据将会很快,因为这样只需要扫描指定的分区。因此,在处理大量数据时,使用分区表是一个非常好的选择。 1、创建表,并使用RANGE COLUMNS分区 按创建时间…...