当前位置: 首页 > news >正文

【区块链安全 | 第三十九篇】合约审计之delegatecall(一)

文章目录

    • 外部调用函数
      • call
      • delegatecall
    • call 与 delegatecall 的区别示例
      • 部署后初始状态
      • 调用B.testCall()函数
      • 调用B.testDelegatecall()函数
      • 区别总结
    • 漏洞代码
    • 代码审计
    • 攻击代码
    • 攻击原理解析
    • 攻击流程
    • 修复建议
    • 审计思路

在这里插入图片描述

外部调用函数

在 Solidity 中,常见的两种底层外部函数调用方式是:call 和 delegatecall。

说明:callcode 已在 Solidity 0.5.0 版本后弃用,不再推荐使用,因此本文不再介绍。

call

call 是一种底层调用方法,适用于向其他合约发送消息或调用函数,同时也支持附带以太币(Ether)。它语法灵活,常用于动态调用。

(bool success, bytes memory data) = target.call{value: msg.value}(abi.encodeWithSignature("func(uint256)", 123));

特点:
1.使用的是目标合约的代码和存储环境;
2.当前合约的 msg.sender 和 msg.value 不会传递给被调用合约;
3.返回值为 (bool success, bytes memory data),失败时不会自动回退(revert),需手动处理;
4.常用于与未知接口或外部插件合约交互(如代理合约);
5.可发送 Ether,适用于多种场景。

delegatecall

delegatecall 也是底层调用方式,但与 call 不同,其执行上下文是当前合约的环境。

(bool success, bytes memory data) = target.delegatecall(abi.encodeWithSignature("func(uint256)", 123));

特点:
1.调用目标合约的代码,但使用的是当前合约的存储(storage)、msg.sender 和 msg.value;
2.目标合约不应定义自己的状态变量,否则可能引发存储冲突;
3.常用于代理合约(Proxy Pattern)与可升级合约场景;
4.存在安全风险,需谨慎使用被调用合约,防止覆盖关键变量。

call 与 delegatecall 的区别示例

我们通过一个对比实验,直观理解两者在执行环境中的差异。

编写并部署如下的 A 合约:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;contract A {address public a;function test() public returns (address b) {b = address(this); // 获取当前合约地址a = b;             // 保存到状态变量 a 中}
}

在这里插入图片描述

合约部署完成后,记录合约 A 地址为 0xcD6a42782d230D7c13A74ddec5dD140e55499Df9。

我们将 A 合约地址填入 B 合约中,并部署如下代码:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;contract B {address public a;// A 合约地址address Aaddress = address(0xcD6a42782d230D7c13A74ddec5dD140e55499Df9);// 使用 call 调用 A.test(),并检查返回值function testCall() public {(bool success, ) = Aaddress.call(abi.encodeWithSignature("test()"));require(success, "call failed");}// 使用 delegatecall 调用 A.test(),并检查返回值function testDelegatecall() public {(bool success, ) = Aaddress.delegatecall(abi.encodeWithSignature("test()"));require(success, "delegatecall failed");}
}

部署后初始状态

在未调用任何函数前,查看合约 A 和 B 中 a 变量的值。

A 合约的 a 为地址 0(即未被赋值):

在这里插入图片描述

B 合约的 a 同样为地址 0:

在这里插入图片描述

当我们分别调用 B.testCall() 和 B.testDelegatecall() 时,它们都会以不同的方式调用 A 合约中的 test() 函数。

让我们观察在这两种调用方式下,A 合约和 B 合约中的 a 变量会发生怎样的变化。

调用B.testCall()函数

我们首先调用 B.testCall() 函数:

在这里插入图片描述

调用完成后,我们先查看 B 合约中 address a 的值,发现它并未发生变化:

在这里插入图片描述

接下来我们查看 A 合约中的 address a,可以看到它已经被赋值,当前值为 0xcD6a42782d230D7c13A74ddec5dD140e55499Df9,与我们之前部署的 A 合约地址一致:

在这里插入图片描述

也就是说,当合约 B 使用 call 函数调用合约 A 的外部函数时,变量 a 的赋值结果来源于合约 A 在其自身上下文中执行操作后的返回值。

由此我们可以得出结论:当合约 B 通过 call 函数调用外部函数时,执行的是被调用合约 A 的代码逻辑,并在被调用合约的存储上下文中完成操作,因此不会影响当前调用合约自身的状态数据。

调用B.testDelegatecall()函数

先重新部署 A 和 B 合约(以清除旧数据)

在调用 B.testDelegatecall() 函数之前,先查看 A 合约中 address a 的值,尚未赋值:

在这里插入图片描述

可以看到,B 合约中的 address a 也尚未赋值,同时我们确认当前 B 合约的地址为:0x5FD6eB55D12E759a21C09eF703fe0CBa1DC9d88D:

在这里插入图片描述

接下来我们调用 B.testDelegatecall() 函数:

在这里插入图片描述

调用之后,我们查看 B 合约中 address a 的值,可以看到它已被赋值为 0x5FD6eB55D12E759a21C09eF703fe0CBa1DC9d88D,也就是当前 B 合约的地址:

在这里插入图片描述

随后我们再次查看 A 合约中的 address a,结果发现其值并未发生改变:

在这里插入图片描述

因此,当我们使用 B.testDelegatecall() 调用 A.test() 时,test 函数的代码逻辑是在 B 合约的环境中执行的,实际上是将 A 合约中的 test() 函数的代码带入 B 合约执行。因此,B 合约的地址被赋值给了变量 a,但这一操作并不会影响 A 合约中的数据。

区别总结

1.当合约 B 使用 call 调用合约 A 的外部函数时,调用发生在合约 A 的上下文中,返回的结果来自合约 A 执行后的值,且不会影响合约 B 的存储。调用时,合约 B 的状态不会受到影响。

2.当合约 B 使用 delegatecall 调用合约 A 的函数时,执行发生在合约 B 的上下文中,且所有的存储操作都会影响 B 合约的状态而非 A 合约。因此,B 合约的地址被赋值给了 a,而 A 合约的数据保持不变。

3.call 是在被调用合约的环境中执行的,而 delegatecall 则是在调用合约的环境中执行,且会修改调用合约的存储。

漏洞代码

存在一漏洞代码如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;// 定义一个名为 Lib 的合约
contract Lib {address public owner;// pwn 函数会将合约的 owner 设置为调用者的地址function pwn() public {owner = msg.sender; // 将合约的 owner 地址设置为调用者(msg.sender)}
}// 定义一个名为 HackMe 的合约
contract HackMe {address public owner; // 合约的拥有者Lib public lib; // 引用 Lib 合约的地址// 构造函数,接收一个 Lib 合约的地址作为参数constructor(Lib _lib) {owner = msg.sender; // 设置 HackMe 合约的拥有者为部署者lib = Lib(_lib); // 初始化 Lib 合约的地址}// fallback 函数,当合约接收到以太币时,执行 delegatecall 调用 Lib 合约的 pwn 函数fallback() external payable {address(lib).delegatecall(msg.data); // 使用 delegatecall 调用 Lib 合约的函数,并传递调用的数据}
}

代码审计

上述代码中,Lib 合约包含一个 pwn() 函数,其作用是将合约中的 owner 设置为当前调用者的地址(msg.sender)。

HackMe 合约维护了一个 owner 变量和一个 Lib 合约实例 lib。在构造函数中,lib 的地址被初始化,同时将 owner 设置为部署者。

当 HackMe 合约收到以太币或被调用但函数签名未匹配时,fallback() 函数会触发,并通过 delegatecall 调用 Lib 合约中的方法,并将调用数据 msg.data 传递进去。

由于 delegatecall 会在当前合约(即 HackMe)的上下文中执行目标合约(即 Lib)的代码,攻击者可以通过调用 HackMe.pwn() 来执行 Lib.pwn(),从而将 HackMe 合约中的 owner 更改为自己。

攻击代码

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;// Attack 合约
contract Attack {address public hackMe;// 构造函数,通过传入 HackMe 合约地址初始化 hackMeconstructor(address _hackMe) {hackMe = _hackMe;  // 保存 HackMe 合约的地址}// 攻击函数,通过调用 HackMe 合约的 pwn() 函数来执行攻击(存在这个函数吗?接着往下看)function attack() public {hackMe.call(abi.encodeWithSignature("pwn()"));}
}

攻击原理解析

我们先回顾一下 fallback 函数的触发时机:

  • 向合约地址直接发送以太币时;

  • 调用合约中不存在的函数时。

在本攻击场景中,attack() 函数调用 HackMe.pwn(),但 HackMe 中并未定义该函数,于是 fallback 被触发。fallback 中的 delegatecall(msg.data) 使用调用数据 “pwn()” 去调用 Lib.pwn(),而 Lib 中恰好存在该函数。

关键点在于:由于使用的是 delegatecall,所以 Lib.pwn() 实际是在 HackMe 的上下文中执行,修改的也是 HackMe 的存储空间。更具体地说,pwn() 函数修改的是第一个状态变量 owner,刚好与 HackMe 中的存储位置匹配,于是 HackMe 的 owner 被成功篡改。

简而言之,攻击者等于是将 Lib.pwn() 拿到 HackMe 合约中执行,实现了对 HackMe 控制权的劫持。

攻击流程

我们以角色 User(受害者)和 Attacker(攻击者)为例,梳理整个攻击过程如下:

1、User 部署 Lib 合约;

2、User 部署 HackMe 合约,并将 Lib 合约地址作为构造参数传入;

3、Attacker 部署 Attack 合约,并传入 HackMe 合约地址;

4、Attacker 调用 Attack.attack(),从而通过 delegatecall 执行 Lib.pwn();

5、HackMe 合约中的 owner 被成功更改为 Attacker。

6、Attacker 可提取合约中所有的 ETH 或 Token;升级合约逻辑为恶意代码等。

修复建议

通过这个例子我们可以清晰看到 delegatecall 带来的安全隐患 —— 如果调用的外部合约不可信或不受控,很可能造成严重的数据篡改或权限劫持问题。因此,在设计合约架构时,应注意以下两点。

1.在使用 delegatecall 时,应确保被调用合约的地址是可信且不可由外部用户控制的。推荐的做法是将目标地址硬编码(写死一个你自己部署、你知道安全的合约地址),或通过白名单机制进行管理,防止恶意地址注入。

如果目标地址是外部可控的,会发生什么?

举个例子:

fallback() external payable {address(_someUserInput).delegatecall(msg.data);
}

假设上面这段代码的 _someUserInput 是用户传进来的地址,此时攻击者可以传一个他部署的恶意合约地址进来,然后通过 delegatecall,在你的合约中执行他的恶意代码,直接改写你合约里的变量,比如 owner、余额等。

2.在复杂合约中使用 delegatecall 时,应确保调用者与被调用合约之间的存储结构保持一致。特别是变量的声明顺序和类型必须严格对应,否则容易因存储插槽错位而导致意外的数据覆盖或逻辑错误。

为什么?这是因为 delegatecall 有一个关键特性:当涉及 storage 变量的修改时,变量的赋值是基于存储插槽的位置(slot)而不是变量名进行的。

举例来说:

1.在 A 合约中,address c 被存储在 slot0,而 address a 被存储在 slot1;

2.在 B 合约中,address a 被存储在 slot0,而 address c 被存储在 slot1;

3.当 B 合约通过 delegatecall 调用 A 合约的 test 函数时,该函数原本用于修改 A 合约中的变量 a,即 slot1 中的数据;

4.然而,在 delegatecall 的上下文中,slot1 实际映射的是 B 合约中的变量 c,因此最终被修改的是 B 合约中的 c,而不是预期的 a。

审计思路

1.在审计中,如发现合约使用了 delegatecall,需重点检查目标合约地址是否有被攻击者控制的可能。如果地址是可控的,即存在外部调用者传入的风险,应视为高危漏洞。

2.若被调用的合约中包含对 storage 变量的修改,审计者应对比其与调用方合约的变量声明顺序和存储插槽分布,确认两者结构是否一致,避免 delegatecall 引发变量误覆盖或权限篡改问题。

最后,推荐继续阅读【区块链安全 | 第四十篇】合约审计之delegatecall(二)

相关文章:

【区块链安全 | 第三十九篇】合约审计之delegatecall(一)

文章目录 外部调用函数calldelegatecall call 与 delegatecall 的区别示例部署后初始状态调用B.testCall()函数调用B.testDelegatecall()函数区别总结 漏洞代码代码审计攻击代码攻击原理解析攻击流程修复建议审计思路 外部调用函数 在 Solidity 中,常见的两种底层外…...

Kingbase 常用运维命令总结

一、数据库连接与基础操作 连接指定服务器数据库 ksql -h 主机IP -p 端口号 -U 用户名 -d 数据库名 -W # 示例:连接 IP 为 192.168.1.100 的数据库 ksql -h 192.168.1.100 -p 54321 -U system -d test -W 断开数据库连接 \q 或 exit 查看数据库列表及详细信息…...

从零开始的C++编程 2(类和对象下)

目录 1.构造函数初始化列表 2.类型转换 3.static成员 4.友元 5.内部类 6.匿名对象 1.构造函数初始化列表 ①之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,初始化…...

Java---抽象类与接口

抽象类与接口 前言一、抽象类1.抽象类的概念2.抽象类的语法3.抽象类的特点4.抽象类的操作5.抽象类的作用 二、接口1.接口的概念2.接口语法3.接口的使用与特性4.实现多个接口5.接口之间的继承6.接口的实例(1).对象大小的比较(1).Comparable接口(2).Comparator接口 (2).实现类的克…...

玩转Docker | 使用Docker部署linkding书签管理工具

玩转Docker | 使用Docker部署linkding书签管理工具 前言一、linkding介绍简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署linkding服务下载镜像创建容器检查容器状态检查服务端口设置登录账号与密码安全设置四、访问linkding服务访问linkding…...

K8s 集群网络疑难杂症:解决 CNI 网络接口宕机告警的完整指南

引言 在 Kubernetes 集群运维过程中,网络问题往往是最棘手的故障之一。当你收到一条 [CRITICAL] 网络接口宕机 (172.18.109.55:9100) 的告警,并且告警内容显示 172.18.109.55:9100 的网络接口 cni0 已宕机5分钟 时,这通常意味着你的 Kubernetes 集群中有一个节点的容器网络…...

程序员/运维绘图工具---Mermaid

效果 介绍 Mermaid 是一种基于文本的图表生成工具,通过类似 Markdown 的简洁语法快速创建流程图、甘特图、类图等各类专业图表 应用场景 程序员绘图 系统架构图&代码逻辑可视化 项目管理图 数据可视化 AI辅助生成:LLM生成mermaid代码然后去渲染成…...

《MATLAB实战训练营:从入门到工业级应用》趣味入门篇-用MATLAB画一朵会动的3D玫瑰:从零开始的浪漫编程之旅

《MATLAB实战训练营:从入门到工业级应用》趣味入门篇-🌹用MATLAB画一朵会动的3D玫瑰:从零开始的浪漫编程之旅 你是否想过用代码创造一朵永不凋谢的玫瑰?今天,我将带你走进MATLAB的奇妙世界,用数学公式和编…...

激光院董事长龚赤坤到北京研发中心检查指导工作

4月11日,激光院党委书记、董事长龚赤坤到北京研发中心检查指导工作。 龚赤坤详细了解了北京研发中心的建设情况和科研进展,充分肯定所取得的成绩,对发展寄予厚望,龚赤坤指出北京研发中心的成立正处于激光院加速发展与产业进化的关…...

AbortController:让异步操作随时说停就停

AbortController:让异步操作随时说停就停 一、什么是 AbortController? AbortController 是 JavaScript 在浏览器和部分 Node.js 环境中提供的全局类,用来中止正在进行或待完成的异步操作(如 fetch() 请求、事件监听、可写流、数…...

leetcode572 另一棵树的子树

1.与100、101解法相同 递归: class Solution { private:bool compare(TreeNode* p, TreeNode* q){if(!p && !q) return true;else if(!p || !q) return false;else if(p->val ! q->val) return false;bool leftside compare(p->left, q->lef…...

再看 MPTCP 时的思考

2022 年夏,居家办公时,第一次接手 mptcp 就觉得它不靠谱,以至于我后来搞了 mpudp for DC,再后来我调研了很多 mptcp-based 方案,发现它们都是向善而来,最终灰头土脸而终。mptcp 实则一个坑,业内…...

将三维非平面点集拆分为平面面片的MATLAB实现

将三维非平面点集拆分为平面面片的MATLAB实现 要将三维空间中不在同一平面上的点集拆分为多个平面面片,可以采用以下几种方法: 1. 三角剖分法 (Delaunay Triangulation) 最简单的方法是将点集进行三角剖分,因为三个点总是共面的&#xff1…...

Python(10.2)Python可变与不可变类型内存机制解密:从底层原理到工程实践

目录 一、类型特性引发的内存现象1.1 电商促销活动事故分析1.2 内存机制核心差异 二、内存地址追踪实验2.1 基础类型验证2.2 复合对象实验 三、深度拷贝内存分析3.1 浅拷贝陷阱3.2 深拷贝实现 四、函数参数传递机制4.1 默认参数陷阱4.2 安全参数模式 五、内存优化最佳实践5.1 字…...

华为hcie证书的有效期怎么判断?

在ICT行业,华为HCIE证书堪称含金量极高的“敲门砖”,拥有它往往意味着在职场上更上一层楼。然而,很多人在辛苦考取HCIE证书后,却对其有效期相关事宜一知半解。今天,咱们就来好好唠唠华为HCIE证书的有效期怎么判断这个关…...

【前端】CSS Grid 布局详解

CSS Grid 布局详解(通俗易懂版) 一、概述 CSS Grid 是一种二维布局系统,可以同时控制行和列,相比 Flex(一维布局),更适合用在整体页面布局或复杂模块结构中。 二、基础概念 Grid 容器&#x…...

物美“外贸转内销”极速绿色通道正式开启

「TMT星球」获悉,在国家“提振消费、扩大内需”及“内外贸一体化”战略指引下,物美集团依托自身零售生态优势,打造“云超绿通”专项通道,助力中国优质外贸企业实现“出口转内销”的高效转型,通过极速绿通、线上线下全渠…...

【说明书#1】Node.js 和 npm安装与使用

系统提示 npm 不是内部或外部命令,也不是可运行的程序或批处理文件,也就是 npm 命令无法识别。这个错误通常是因为 Node.js 和 npm 没有正确安装,或者它们的路径没有添加到系统的环境变量中。 解决方法如下: 1. 安装 Node.js 和 npm: 如果你还没有安装 Node.js,可以从…...

【触想智能】安卓工业平板电脑和普通商业平板电脑的区别

安卓工业平板电脑是基于ARM架构开发的一种工业平板电脑,它在自助终端、智能制造、产线车间、智慧物流、商业金融等诸多领域有着广泛的应用。 触想安卓工业平板电脑TPC-A2系列 安卓工业平板电脑和普通商业平板电脑在一些方面存在一些区别,包括设计、硬件规…...

Java基于SSM的课程答疑微信小程序【附源码、文档说明】

博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&#x1f3…...

模板引擎语法-变量

模板引擎语法-变量 文章目录 模板引擎语法-变量(一)在Django框架模板中使用变量的代码实例(二)在Django框架模板中使用变量对象属性的代码实例(三)在Django框架模板中使用变量显示列表 (一&…...

1260 最大公约数

1260 最大公约数 ⭐️难度:中等 🌟考点:GCD 📖 📚 import java.util.Scanner; import java.util.Arrays;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int t …...

Node.js中net模块详解

Node.js 中 net 模块 API 详解 Node.js 的 net 模块提供了基于 TCP/IP 的网络功能,用于创建 TCP 服务器和客户端。以下是 net 模块的所有 API 详解: 1. 创建 TCP 服务器 const net require(net);// 1. 基本服务器 const server net.createServer((s…...

【从零开始学习JVM | 第三篇】虚拟机的垃圾回收学习(一)

堆空间的基本结构 Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时,Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收。 Java 堆是垃圾收集器管理的主要区域,因此也被称作 GC 堆(Garbage Collected Heap&am…...

intellj idea 2024.1

参考资料 激活 https://www.microcharon.com/tech/5.htmlja-netfilter-all下载地址:https://drive.microcharon.com/OneDrive/Software/JetBrains%20ja-netfilter-all%20Build%202024.1.11.zip 步骤及问题 下载后:安全前确保旧版本的idea已经卸载。安…...

redis之缓存击穿

一、前言 本期我们聊一下缓存击穿,其实缓存击穿和缓存穿透很相似,区别就是,缓存穿透是一些黑客故意请求压根不存在的数据从而达到拖垮系统的目的,是恶意的,有针对性的。缓存击穿的情况是,数据确实存在&…...

Node.js中path模块详解

Node.js path 模块全部 API 详解 Node.js 的 path 模块提供了处理文件路径的工具函数,支持跨平台路径操作。以下是 path 模块的所有 API 详解: 1. 路径解析与操作 const path require(path);// 1. 路径连接 const fullPath path.join(__dirname, fi…...

重构艺术 | 内联与查询替代临时变量

重构艺术 | 内联与查询替代临时变量 在代码重构的殿堂里,临时变量常常扮演着双面角色:既是代码清晰的助力器,也可能成为代码腐败的温床。本文将深入探讨两种处理临时变量的重要手法:内联临时变量(Inline Temp&#xf…...

数据分析-数据预处理

数据分析-数据预处理 处理重复值 duplicated( )查找重复值 import pandas as pd apd.DataFrame(data[[A,19],[B,19],[C,20],[A,19],[C,20]],columns[name,age]) print(a) print(--------------------------) aa.duplicated() print(a)只判断全局不判断每个 any() import p…...

Java基础 4.12

1.方法的重载(OverLoad) 基本介绍 Java中允许同一个类,多个同名方法的存在,但要求形参列表不一致! 如 System.out.println(); out是PrintStream类型 重载的好处 减轻了起名的麻烦减轻了记名的麻烦 2.重载的快速入…...

PostgreSQL有类似oracle的move表吗

PostgreSQL有类似oracle的move表吗 PostgreSQL 提供了类似 Oracle MOVE 表功能的重组操作,但实现方式和具体命令有所不同。以下是详细对比和 PostgreSQL 中的实现方案: 一 Oracle MOVE 与 PostgreSQL 对比 特性Oracle MOVEPostgreSQL 等效操作主要用途…...

AUTO-RAG: AUTONOMOUS RETRIEVAL-AUGMENTED GENERATION FOR LARGE LANGUAGE MODELS

Auto-RAG:用于大型语言模型的自主检索增强生成 单位:中科院计算所 代码: https://github.com/ictnlp/Auto-RAG 拟解决问题:通过手动构建规则或者few-shot prompting产生的额外推理开销。 贡献:提出一种以LLM决策为中…...

ABC-CNN-GRU-Attention、CNN-GRU-Attention、ABC-CNN-GRU和CNN-GRU四类对比模型多变量时序预测

人工蜂群算法四模型对比!ABC-CNN-GRU-Attention系列四模型多变量时序预测 目录 人工蜂群算法四模型对比!ABC-CNN-GRU-Attention系列四模型多变量时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 本研究针对多变量时间序列预测任务&#xf…...

ssh 免密登录服务器(vscode +ssh 免密登录)

每次打开vscode连接服务器都需要输入密码,特别繁琐。 然后自己在网上翻阅了一下教程,发现说的内容比较啰嗦,而且个人感觉非常有误导性倾向。 因此自己直接干脆写一个简便易懂的教程算了。 (以经过本人亲测,真实可靠&am…...

Elasticsearch 系列专题 - 第七篇:实战项目

理论学习固然重要,但实战才能真正巩固知识。本篇将通过两个项目,带你从需求分析到实现,体验 Elasticsearch 在真实场景中的应用。 1. 项目一:日志分析系统 1.1 需求分析与架构设计 需求: 实时采集服务器日志。按时间和日志级别(INFO、ERROR)分析。可视化错误趋势。架构…...

C++初阶-类和对象(上)

本章内容相对于之后的类和对象中和下都比较简单,但是整体还是有些难度的。 目录 1.类的定义 1.1类定义格式 1.2访问限定符 1.3类域 2.实例化 2.1实例化概念 2.2对象大小 3.this指针 4.练习 4.1选择题1 4.2选择题2 5.总结 1.类的定义 1.1类定义格式 &am…...

(十九)安卓开发中的Application类的使用详解

在 Android 开发中,Application 类是一个全局的单例类,代表应用进程本身。它常用于初始化全局资源、维护应用级别的状态和注册全局生命周期回调。以下是详细讲解和代码示例: 一、自定义 Application 类 1. 创建子类 public class MyApplica…...

算法思想之位运算(一)

欢迎拜访:雾里看山-CSDN博客 本篇主题:算法思想之位运算(一) 发布时间:2025.4.12 隶属专栏:算法 目录 滑动窗口算法介绍六大基础位运算符常用模板总结 例题位1的个数题目链接题目描述算法思路代码实现 比特位计数题目链接题目描述…...

十八、TCP多线程、多进程并发服务器

1、TCP多线程并发服务器 服务端&#xff1a; #include<stdio.h> #include <arpa/inet.h> #include<stdlib.h> #include<string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <pthread.h>…...

『生成内容溯源系统』详解

生成内容溯源系统详解 1. 定义与核心目标 生成内容溯源系统&#xff08;Generative Content Provenance System&#xff09;是指能够追踪AI生成内容的来源、生成过程、版权归属及修改历史的技术体系。其核心目标是&#xff1a; 验证真实性&#xff1a;证明内容由特定AI模型生…...

mac 解压 nsz 文件

nsz 地址 下载 nsz PIP 套餐 使用以下命令安装仅限 Console 的版本&#xff1a; pip3 install --upgrade nsz使用以下命令安装 GUI 版本&#xff1a; pip3 install --upgrade nsz[gui]解压 nsz 文件 nsz -D 文件路径...

Python进阶(3):函数(接上篇)

上一篇我们初步介绍python中函数的定义与调用 Python进阶(2):函数-CSDN博客 这里继续: 关键字参数: 形参1实参1,形参2实参2,...... 关键字参数是指使用形式参数的名字来确定输入的参数值。通过该方式指定实际参数时,不再需要与形式参数的位置完全一致。只要将参数名写正确…...

卒/兵过河前的判断和走法触发器优化

兵(卒)&#xff1a;兵(卒)在未过河前&#xff0c;只能向前一步步走&#xff0c;过河以后&#xff0c;除不能后退外&#xff0c;允许左右移动&#xff0c;但也只能一次一步。 迷你世界地图已上传 优化...

生物信息Rust-01

前言-为什么想学Rust&#xff1f; 一直想多学一门编译语言&#xff0c;主要有几个原因吧&#xff08;1. 看到一位老师实验室要求需要掌握一门编译语言&#xff1b;2. 自己享想试着开发一些实用的生信工具&#xff0c;感觉自己现在相比于数据分析&#xff0c;探索生物学层面的意…...

基于HTML + jQuery + Bootstrap 4实现(Web)地铁票价信息生成系统

地铁票价信息表生成系统 1. 需求分析 1.1 背景 地铁已经成为大多数人出行的首选,北京地铁有多条运营线路, 截至 2019 年 12 月,北京市轨道交通路网运营线路达 23 条、总里程 699.3 公里、车站 405 座。2019 年,北京地铁年乘客量达到 45.3 亿人次,日均客流为 1241.1 万人次…...

智慧水务项目(八)基于Django 5.1 版本PyScada详细安装实战

一、说明 PyScada&#xff0c;一个基于Python和Django框架的开源SCADA&#xff08;数据采集与监视控制系统&#xff09;系统&#xff0c;采用HTML5技术打造人机界面&#xff08;HMI&#xff09;。它兼容多种工业协议&#xff0c;如Modbus TCP/IP、RTU、ASCII等&#xff0c;并具…...

DeepSeek在消防救援领域的应用解决方案

DeepSeek在消防救援领域的应用解决方案 一、火灾风险动态感知与早期预警 火灾风险动态感知与早期预警是智慧消防的关键环节&#xff0c;DeepSeek通过多模态数据分析&#xff0c;融合烟雾传感器、热成像摄像头和气体浓度检测等数据&#xff0c;能够识别传统阈值法难以捕捉的火…...

VSCode CMake调试CPP程序

文章目录 1 安装C与CMake插件2 配置CMakeLists.txt3 使用CMake编译调试3.1 编译3.2 调试 4 自定义构建调试参考 1 安装C与CMake插件 C插件 CMake插件 2 配置CMakeLists.txt 编写测试程序 #include<iostream>int main(int argc, char const *argv[]) {int a 1, b 2;i…...

AI Agent工程师认证-学习笔记(3)——【多Agent】MetaGPT

学习链接&#xff1a;【多Agent】MetaGPT学习教程 源代码链接&#xff08;觉得很好&#xff0c;star一下&#xff09;&#xff1a;GitHub - 基于MetaGPT的多智能体入门与开发教程 MetaGPT链接&#xff1a;GitHub - MetaGPT 前期准备 1、获取MetaGPT &#xff08;1&#xff…...

Spring AI 结构化输出详解

一、Spring AI 结构化输出的定义与核心概念 Spring AI 提供了一种强大的功能&#xff0c;允许开发者将大型语言模型&#xff08;LLM&#xff09;的输出从字符串转换为结构化格式&#xff0c;如 JSON、XML 或 Java 对象。这种结构化输出能力对于依赖可靠解析输出值的下游应用程…...