free源码

文章目录

  • free源码调试
    • main_arena结构:
    • free_hook
    • tcache
      • tcache的结构
      • free_chunk进入tcache:
    • fastbin
    • unlink + 合并
    • top

free源码调试

main_arena结构:

  1. 整体看一下main_arena的结构:

    image-20240920191211042

    image-20240920191223421

free_hook

  1. free_hook,在glibc-2.34前,在调用free前都会检查free_hook中是否存在指针,如果指针存在就会直接去执行对应的函数,此时的rdi值就是释放的chunk地址(准确来说是用户控制的地址):

    image-20240920104029774

  2. 覆盖free_hook,并伪造适当的rdi的chunk,可以直接getshell,或者free_hook + gadget打ORW

  3. glibc-2.33 和 glibc-2.34 在开头的比较,明显glibc-2.34在free前直接取消了free_hook

    image-20240920105057029

    image-20240920105102251

tcache

tcache的结构

  1. mp_ 结构体,存储了有关tcache的一些全局信息:

    • tcache_count ==> 一个tcache中能放入的chunk的最大个数
    • tcache_bins ==> tcachce中能放入的最大chunk 在counts中对应的下标

    image-20240918212940432

    tcache对应的结构体 tcache_perthread_struct

    • count ==> 在tcachce中,同一size大小的chunk的个数
    • entries ==> 存放tcachce中,一个chunk链的头指针

    下面tcache_entrykey 是用来判断tcache中是否存在double free的(从glibc-2.29开始):

    image-20240918213454939

free_chunk进入tcache:

  1. 堆tcachce部分的处理:

    #glibc-2.29
    size = chunksize (p);
    ····
    check_inuse_chunk(av, p);
    #if USE_TCACHE{size_t tc_idx = csize2tidx (size); //获得 释放的chunk 在count中对应的下标if (tcache != NULL && tc_idx < mp_.tcache_bins) // tcache已经初始化 并且tc_idx在tcache存放chunk的范围内{/* Check to see if it's already in the tcache.  */tcache_entry *e = (tcache_entry *) chunk2mem (p); // 类型转化/* This test succeeds on double free.  However, we don't 100%trust it (it also matches random payload data at a 1 in2^<size_t> chance), so verify it's not an unlikelycoincidence before aborting.  */if (__glibc_unlikely (e->key == tcache)) // 检查key字段,防止double free{tcache_entry *tmp;LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);for (tmp = tcache->entries[tc_idx] ; tmp ; tmp = tmp->next)if (tmp == e) // 如果找到相同的chunk则证明确实存在double free,因为可能key字段相同 但是两个chunk确实是不同的情况 这时就不存在double freemalloc_printerr ("free(): double free detected in tcache 2");/* If we get here, it was a coincidence.  We've wasted afew cycles, but don't abort.  */}if (tcache->counts[tc_idx] < mp_.tcache_count) // 如果对应的count未满 则将chunk进入tcache{tcache_put (p, tc_idx);return;}}}
    #endifstatic __always_inline void
    tcache_put (mchunkptr chunk, size_t tc_idx)// tcache_put没有任何检查
    {tcache_entry *e = (tcache_entry *) chunk2mem (chunk);assert (tc_idx < TCACHE_MAX_BINS);/* Mark this chunk as "in the tcache" so the test in _int_free willdetect a double free.  */e->key = tcache; // 在key字段 置入key值e->next = tcache->entries[tc_idx]; // 头插法tcache->entries[tc_idx] = e; // tcachce链的新头++(tcache->counts[tc_idx]); // 对应的count++
    }

    tcache已经初始化(0x405010) 并且tc_idx在tcache存放chunk的范围内(0x5 < 0x40):

    image-20240920105539167

    先检查key字段,防止释放的chunk重复:

    image-20240920105730066

    如果对应的count未满 则将chunk进入tcache:

    image-20240920110250485

  2. glibc-2.29 和 glibc-2.28 在tcache处理部分的比较,可以看到glibc-2.28 之前对进入tcache的chunk是没有double检查

    image-20240920110647647

    image-20240920110630896

  3. 看一下,对tcache的 next指针加密 ,glibc-2.31 和 glibc-2.32 的 tcachce_put 函数上的比较,从glibc-2.32开始对next字段进行加密

    image-20240920111106044

    这里可以看到 在赋值新的chunk的next指针 时,先调用了 PROTECT_PTR 函数将 chunk的next字段的地址要加密的指针值(原tcache链的头chunk地址)一起传入

    image-20240920111126484

    加密的逻辑:next字段地址右移12位 xor 要加密的值

    解密的逻辑:待解密的指针地址右移12位 xor 待解密的值 (刚好和加密的相逆)。

    这里存在一个利用,在第一个chunk进入tcache时,从tcache->entries[tc_idx]中取出的值一定为0,所以异或的结果 存入新chunk的next字段 直接是next字段的地址右移12位 而chunk地址偏移在 0~0x1000 内的都是公用一个((size_t) pos) >> 12值(tcache_key),所以泄漏最初的chunk的next字段后就能获得tcache_key,从而能控制next字段的值(再取出时要进行解密,所以伪造next字段时要先加密)。

    这里的加密仅针对next字段,在 tcache->entries[tc_idx] 中的头chunk地址,是没有加密的:

    image-20240920111416324

  4. tcache在控制chunk进入对应的链时,是根据其释放时 size字段的大小来确定,所以可以将较小的chunk的size字段值改大,将其释放进入较大的tcache链中,再申请出来时就能造成overlapping(这种方法一般用在fastbin中,因为fastbin中取出chunk时 会检查size字段)。当然如果能直接修改next字段,则可以实现任意地址分配chunk(因为tcache中取出chunk 时不进行size检查 ==> malloc源码 中有体现)。

  5. 另外,经调试发现,tcache的地址是存储在tls段,如果能修改这个值,那么tcache就会转移位置:

    image-20240921113658248

    修改这个值为一个堆地址,那么tcache位置就会改变,再释放的chunk就不会进入原本的tcache了:

    改成一个堆地址:

    image-20240921113825578

    再free一个chunk,看看堆上的变化:

    这里取出了我们伪造的tcache地址

    image-20240921113941124

    最后释放的chunk顺利进入伪造的tcachce中,相当于变向劫持了tcache_perthread_struct,实际的利用可能用不上,远程tls的偏移可能需要爆破:

    image-20240921114100147

    再次申请chunk 也是直接从伪造的tcache 中拿:

    image-20240921114501570

fastbin

  1. 当前面的tcachce占满时,会将一定大小的chunk 放入fastbin中:

      /*If eligible, place chunk on a fastbin so it can be foundand used quickly in malloc.*/if ((unsigned long)(size) <= (unsigned long)(get_max_fast ()) // 释放的chunk大小在fastbin范围内 get_max_fast () ==> 0x80#if TRIM_FASTBINS/*If TRIM_FASTBINS set, don't place chunksbordering top into fastbins*/&& (chunk_at_offset(p, size) != av->top)
    #endif) {if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))<= 2 * SIZE_SZ, 0)|| __builtin_expect (chunksize (chunk_at_offset (p, size))>= av->system_mem, 0)){bool fail = true;/* We might not have a lock at this point and concurrent modificationsof system_mem might result in a false positive.  Redo the test aftergetting the lock.  */if (!have_lock){__libc_lock_lock (av->mutex);fail = (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ|| chunksize (chunk_at_offset (p, size)) >= av->system_mem);__libc_lock_unlock (av->mutex);}if (fail)malloc_printerr ("free(): invalid next size (fast)");}free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);atomic_store_relaxed (&av->have_fastchunks, true);unsigned int idx = fastbin_index(size); // 根据size获取对应的fastbin下标fb = &fastbin (av, idx); // 根据下标拿到 对应fastbin链的地址 这里有指向 对应fastbin链的头chunk的指针/* Atomically link P to its fastbin: P->FD = *FB; *FB = P;  */mchunkptr old = *fb, old2; // old是对应原fastbin链的头chunk的地址if (SINGLE_THREAD_P){/* Check that the top of the bin is not the record we are going toadd (i.e., double free).  */if (__builtin_expect (old == p, 0)) // 进行double free 检查 ,但是仅检查了头chunk 是否与新的chunk相同malloc_printerr ("double free or corruption (fasttop)");p->fd = old; // 头插法*fb = p; // 更新 新的链首}elsedo{/* Check that the top of the bin is not the record we are going toadd (i.e., double free).  */if (__builtin_expect (old == p, 0))malloc_printerr ("double free or corruption (fasttop)");p->fd = old2 = old;}while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))!= old2);/* Check that size of fastbin chunk at the top is the same assize of the chunk that we are adding.  We can dereference OLDonly if we have the lock, otherwise it might have already beenallocated again.  */if (have_lock && old != NULL&& __builtin_expect (fastbin_index (chunksize (old)) != idx, 0))malloc_printerr ("invalid fastbin entry (free)");}
    

    image-20240920115130422

    image-20240920115441009

  2. 在free函数对于fastbin的处理中存在的利用:

    • 利用fastbin 处理double free 仅对链首进行比较,并且fastbin采用的头插法,这里可以绕过检查实现double free ==> free(chunk1) -> free(chunk2)新的链首 -> free(chunk1) ,这样对chunk1就实现了double free

    • 覆盖 global_max_fast(global_max_fast所处的段具有写的权限) 将更大的chunk置入fastbin中处理:

      将global_max_fast改为0x100,将0xa0大小的chunk放入fastbin中处理:

      image-20240920120401732

      这里将释放的chunk的size 与 global_max_fast 比较:

      image-20240920120624521

      拿到下标(idx = 8) 和 main_arena中Yfastbin数组的地址,在一般情况下fastbin中最大的chunk的size是0x80,也就是下标只能到6 ==> 0x80:

      image-20240920121003897

      置入fastbin中(这里gdb没有显示不影响,只要main_arena中有就行了):

      image-20240920121310884

  3. fastbin的fd字段加密处理,glibc-2.31 和 glibc-2.32 比较,可以看到从glibc-2.32开始 对fastbin的fd字段 也进行了加密(同上面的tcache加密模式),所以要利用的必须先 泄漏堆地址 拿到右移12位的那个异或值 后才能伪造fd字段,进行任意地址申请chunk:

    image-20240920121732949

    image-20240920121747007

unlink + 合并

  1. 释放的chunk 在tcache中已经装满,并且不在fastbin的范围内时,会先进行合并操作。结合前面堆tcache和fastbin的处理,可以发现处于 tcache 和 fastbin中的chunk不会被其高地址的chunk标记为被释放(即相邻的高地址处的chunk的prev_inuse位一直为1),所以tcache 和 fastbin中的chunk 是不可能被合并的:

    /*Consolidate other non-mmapped chunks as they arrive.*/else if (!chunk_is_mmapped(p)) {/* If we're single-threaded, don't lock the arena.  */if (SINGLE_THREAD_P)have_lock = true;if (!have_lock)__libc_lock_lock (av->mutex);nextchunk = chunk_at_offset(p, size);/* Lightweight tests: check whether the block is already thetop block.  */if (__glibc_unlikely (p == av->top))malloc_printerr ("double free or corruption (top)");/* Or whether the next chunk is beyond the boundaries of the arena.  */if (__builtin_expect (contiguous (av)&& (char *) nextchunk>= ((char *) av->top + chunksize(av->top)), 0))malloc_printerr ("double free or corruption (out)");/* Or whether the block is actually not marked used.  */if (__glibc_unlikely (!prev_inuse(nextchunk)))malloc_printerr ("double free or corruption (!prev)");nextsize = chunksize(nextchunk);if (__builtin_expect (chunksize_nomask (nextchunk) <= 2 * SIZE_SZ, 0)|| __builtin_expect (nextsize >= av->system_mem, 0))malloc_printerr ("free(): invalid next size (normal)");free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);/* consolidate backward */if (!prev_inuse(p)) { // 向后合并(向低地址)prevsize = prev_size (p); // 拿到该chunk的prev_size字段的值,如果后一个chunk被释放了,那么该chunk的prev_size字段会启用(存储后一个chunk的大小,即对应其size值)size += prevsize;p = chunk_at_offset(p, -((long) prevsize)); // 拿到后一个chunk地址if (__glibc_unlikely (chunksize(p) != prevsize)) // 合并unlink前检查 待合并的chunk的size是否与前一个chunk(待释放的chunk) 的prev_size字段值相同malloc_printerr ("corrupted size vs. prev_size while consolidating");unlink_chunk (av, p); // 解链}if (nextchunk != av->top) // 保证相邻的高地址处的chunk不是top chunk{ /* get and clear inuse bit */nextinuse = inuse_bit_at_offset(nextchunk, nextsize);/* consolidate forward */if (!nextinuse) {  // 向前合并(向高地址)unlink_chunk (av, nextchunk); // 解链size += nextsize;} elseclear_inuse_bit_at_offset(nextchunk, 0);/*Place the chunk in unsorted chunk list. Chunks arenot placed into regular bins until after they havebeen given one chance to be used in malloc.*/bck = unsorted_chunks(av);fwd = bck->fd;if (__glibc_unlikely (fwd->bk != bck)) // unsorted bin链的检查malloc_printerr ("free(): corrupted unsorted chunks");p->fd = fwd;p->bk = bck;if (!in_smallbin_range(size)){p->fd_nextsize = NULL;p->bk_nextsize = NULL;}bck->fd = p;fwd->bk = p;set_head(p, size | PREV_INUSE);set_foot(p, size);check_free_chunk(av, p);}/*If the chunk borders the current high end of memory,consolidate into top*/else { // 与top chunk相邻的,直接合并进入top chunksize += nextsize;set_head(p, size | PREV_INUSE);av->top = p;check_chunk(av, p);}/* Take a chunk off a bin list.  */
    static void unlink_chunk (mstate av, mchunkptr p)
    {if (chunksize (p) != prev_size (next_chunk (p))) // 又做一次待合并的chunk的size 和 prev_size 的检查(确保向前合并(向高地址))malloc_printerr ("corrupted size vs. prev_size");mchunkptr fd = p->fd; // 找到链上 chunk_p的前一个chunkmchunkptr bk = p->bk; // 找到链上 chunk_p的后一个chunkif (__builtin_expect (fd->bk != p || bk->fd != p, 0)) // 双向链表检查 一个指针不存在都错误malloc_printerr ("corrupted double-linked list");fd->bk = bk; // 将p解链 bk->fd = fd; // 将p解链 if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL) // large bin chunk{if (p->fd_nextsize->bk_nextsize != p|| p->bk_nextsize->fd_nextsize != p)malloc_printerr ("corrupted double-linked list (not small)");if (fd->fd_nextsize == NULL){if (p->fd_nextsize == p)fd->fd_nextsize = fd->bk_nextsize = fd;else{fd->fd_nextsize = p->fd_nextsize;fd->bk_nextsize = p->bk_nextsize;p->fd_nextsize->bk_nextsize = fd;p->bk_nextsize->fd_nextsize = fd;}}else{p->fd_nextsize->bk_nextsize = p->bk_nextsize;p->bk_nextsize->fd_nextsize = p->fd_nextsize;}}
    }
    

    glibc-2.28 和 glibc-2.29 在合并前对prev_size检查的,区别:

    image-20240920123604102

    image-20240920123618647

    但是glibc-2.28 在unlink里面 对待合并的chunk的size 和 prev_size 做了检查(这个检查单纯针对待合并的chunk ):

    image-20240920165224646

    到glibc-2.25 以及之前是没有这个检查的:

    image-20240920165415022

  2. 这里看一下在glibc-2.27 合并时如果 size 和 prev_size 不匹配会怎么样:

    伪造蓝色chunk的prev_inuse位 和 prev_size 字段,并将tcache伪造满:

    image-20240920172339115

    free掉蓝色chunk ,其会直接向上合并到unsorted bin中的chunk:

    调试,这里检查到 待合并的chunk 0x405250 的size 与 prev_size(相邻高地址的chunk 即图中的绿色chunk的prev_size) 不同:

    image-20240920172543803

    如果改为相同:

    image-20240920172809921

    检查顺利通过,随后进入unlink:

    image-20240920172801347

    进入unlink 后进行 双向链表检查,检查完成后顺利 解链:

    image-20240920172952926

    最后完成 合并 + unlink 进入到unsorted bin中,实现overlapping:

    image-20240920173237270

  3. 所以这里可以得出一个利用:伪造chunk 后利用 unlink + 合并 实现overlapping 只需要提前泄漏heap地址能覆盖prev_inuse位为0即可:

    在glibc-2.28即以前,向前合并,和向后和并都适用:

    这里以glibc-2.27演示向前合并:

    伪造好chunk_0x21 和 待释放的chunk的prev_inuse 和prev_size字段:

    image-20240920174151972

    通过伪造的prev_size 找到了伪造的chunk,再通过伪造的chunk_0x21 找到 prev_size(伪造的0x20) ,两则比较通过 size == prev_size 检查

    image-20240920174450659

    随后 利用伪造的 fd 和 bk 通过双向链表检查:

    image-20240920174809547

    最后顺利进入unsorted bin 中(因为我们没有动unsorted bin 所以后面放入unsorted bin时的检查肯定能顺利通过):

    image-20240920181409664

    image-20240920174904305

    这里向后合并造成overlapping的,需要能修改chunk的size字段,参考这篇:伪造unsortedbin释放时 top chunk的衔接问题

    再看glibc-2.29以及之后的libc是否同样适用,以glibc-2.29实验:

    同样的方式伪造好chunk:

    image-20240920180153899

    到这里 由于释放的chunk的prev_size位和待合并的chunk的size不相等 导致检查不能通过:

    image-20240920180326226

    但是如果将伪造的chunk 的size给成0x150,即伪造成如下的样式:

    image-20240920180638029

    第一个检查顺利通过:

    image-20240920180608639

    随后进入unlink_chunk:

    检查待合并的chunk(即我们伪造的chunk) 和 其相邻的高地址chunk的prev_size位(即蓝色chunk的prev_size) 位,通过检擦:

    image-20240920180814574

    随后双向链表的检查也通过:

    image-20240920181020944

    最后 进入到unsorted bin中:

    image-20240920181501167

    注意点:unlink合并 进入unsorted bin 最后时没有将prev_size字段清空的,这样在我们无法伪造相邻高地址的chunk的prev_size时 可以借此先free掉chunk填充prev_size字段后,再申请回来,就会出现一个天然的prev_size值

    这种适合在我们可以控制相邻的高地址的chunk的prev_inuse位,但是不能控制其prev_size字段 的情况下时使用(后面的例题):

    这里先释放掉chunk1,将其size置入到相邻的高地址的chunk的prev_size中:

    image-20240920182405577

    再将其申请回来,这时相邻的高地址的chunk的prev_size中就填充上了该chunk的size大小

    image-20240920182538210

top

  1. tcache填满,不属于fastbin,且与top chunk相邻时,会直接向top chunk合并:

        else { // 与top chunk相邻的,直接合并进入top chunksize += nextsize;set_head(p, size | PREV_INUSE);av->top = p;check_chunk(av, p);}
    

    计算新的top chunk的size,释放的chunk地址作为新的top chunk地址,放入main_arena的top字段中:

    image-20240920190826633

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1541736.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

在 Windows 11 中,可以通过修改注册表来更改系统的自动更新时间设置

regedit 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings FlightSettingsMaxPauseDays 36524

AI少女/HS2甜心选择2 仿崩铁人物卡全合集打包

内含AI少女/甜心选择2 仿崩铁【崩坏 星穹铁道 】角色卡全合集打包共6张 内含&#xff1a;布洛妮娅镜流卡芙卡希儿停云银狼 下载地址&#xff1a; https://www.51888w.com/375.html 部分演示图&#xff1a;

项目第六弹:虚拟机管理模块、路由匹配模块

项目第六弹&#xff1a;虚拟机管理模块、路由匹配模块 一、虚拟机管理模块的设计1.什么是虚拟机&#xff1f;2.借助MySQL来理解一下3.如何整合&#xff1f;【埋下伏笔】 二、RabbitMQ为何要有虚拟机1.从业务角度来讲2.步步探索1.优点2.结合业务适用场景和需求3.发掘真正的原因4…

NoSql数据库Redis知识点

数据库的分类 关系型数据库 &#xff0c;是建立在关系模型基础上的数据库&#xff0c;其借助于集合代数等数学概念和方法来处理数据库 中的数据主流的 MySQL 、 Oracle 、 MS SQL Server 和 DB2 都属于这类传统数据库。 NoSQL 数据库 &#xff0c;全称为 Not Only SQL &a…

Python学习——【4.1】数据容器:list列表

文章目录 【4.1】数据容器&#xff1a;list列表一、数据容器入门二、数据容器&#xff1a;list 列表&#xff08;一&#xff09;列表的定义&#xff08;二&#xff09;列表的下标索引&#xff08;三&#xff09;列表的常用操作&#xff08;1&#xff09;列表的查询功能&#xf…

RAG+Agent人工智能平台:RAGflow实现GraphRA知识库问答,打造极致多模态问答与AI编排流体验

1.RAGflow简介 全面优化的 RAG 工作流可以支持从个人应用乃至超大型企业的各类生态系统。大语言模型 LLM 以及向量模型均支持配置。基于多路召回、融合重排序。提供易用的 API&#xff0c;可以轻松集成到各类企业系统。支持丰富的文件类型&#xff0c;包括 Word 文档、PPT、exc…

Vue3入门 - ElementPlus中左侧菜单和Tabs菜单组合联动效果

在Vue3中&#xff0c;ElementPlus是使用比较广泛的UI组件库&#xff0c;提供了丰富的界面元素支持项目开发需求。在后台管理系统中&#xff0c;左侧或顶部的菜单栏通常包含多个子菜单项&#xff0c;通过菜单的展开和收缩功能&#xff0c;用户可以方便地查看或隐藏不需要的菜单项…

数字世界中的浪漫:揭秘会跳动的爱心

在编程的世界里&#xff0c;复杂的技术可以与艺术产生美妙的碰撞。无论是通过代码实现动态效果&#xff0c;还是用算法绘制图案&#xff0c;程序员都可以成为数字艺术的创作者。而今天&#xff0c;我们将通过 Python 的强大 GUI 工具库 Tkinter&#xff0c;用简单的代码生成一颗…

U-Boot顶层Makefile详解

直接参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81 本文仅作为个人笔记使用&#xff0c;方便进一步记录自己的实践总结。 上一章我们详细的讲解了 uboot 的使用方法&#xff0c;其实就是各种命令的使用&#xff0c;学会 uboot 使用以后就可以尝试移植 uboot 到自己的开发…

linux操作系统的基本命令

1.linux下的文件系统 在linux操作目录下没有像window操作系统下盘符的概念,只有一个根目录/,所有文件目录都在它的下面 linux的目录结构: 在Linux系统中: 文件都从跟目录开始的,用/表示文件名称区分大小写路径都是以/俩进行分隔(windown用\分隔)以.开头的文件为隐藏文件 Li…

鸿蒙开发之ArkUI 界面篇 十七 购物综合案例

layoutWeight:子元素与兄弟元素主轴方向按照权重进行分配,参数是联合类型&#xff0c;数字或者是字符串&#xff0c;在指定的空间占多少份额&#xff0c;数字越大&#xff0c;表示在空间中占用的份额越多&#xff0c;如果父容器的子组件没有别的指定&#xff0c;剩下的空间全部…

10分钟一条童装走秀爆款Ai视频,小白轻松上手,新蓝海赛道,竞争小机会多!

今天我要给大家带来一个超级有趣的项目——童装走秀AI视频制作。 这不仅是一个充满创意的项目&#xff0c;而且操作简单&#xff0c;即使是视频制作的新手也能轻松上手。 更重要的是&#xff0c;这个项目竞争小&#xff0c;变现机会多&#xff0c;是进入新蓝海赛道的绝佳机会…

C++类之set与get理解

在类中&#xff0c;我们尝尝将一些变量设置为private或者protect里面&#xff0c;而我们经常会遇到在主函数&#xff08;main.cpp&#xff09;使用到这些private变量&#xff0c;而往往我们会下意识地在主函数直接调用在private里面的变量&#xff0c;但现实比较残酷&#xff0…

【linux】nice命令

Linux中的nice命令是一个强大的工具&#xff0c;用于调整进程的优先级&#xff0c;进而影响它们在CPU上的资源分配和执行顺序。以下是关于nice命令的详细解释&#xff0c;包括其用途、语法、参数、示例以及使用建议。 一、用途 nice命令主要用于控制进程在CPU上的调度优先级&…

K8S介绍+集群部署

Kubernetes介绍 官网&#xff1a;https://kubernetes.io/ 一、应用部署方式演变 1、传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其他技术的参与 缺点&#xff1a;不能为应用程序定义资源使用边界&a…

【论文笔记】BEVNeXt: Reviving Dense BEV Frameworks for 3D Object Detection

原文链接&#xff1a;https://arxiv.org/pdf/2312.01696 简介&#xff1a;最近&#xff0c;在摄像头3D目标检测任务中&#xff0c;基于查询的Transformer解码器正在超越传统密集BEV方法。但密集BEV框架有着更好的深度估计和目标定位能力&#xff0c;能全面精确地描绘3D场景。本…

初始网络编程(下)

所属专栏&#xff1a;Java学习 1. TCP 的简单示例 同时&#xff0c;由于 TCP 是面向字节流的传输&#xff0c;所以说传输的基本单位是字节&#xff0c;接受发送都是使用的字节流 方法签名 方法说明 Socket accept() 开始监听指定端口&#xff08;创建时绑定的端口&…

Navicat导入Sql文件至Mysql数据库,事务失效

Mysql 版本&#xff1a;8.0.39 Navicat 版本&#xff1a;17.x、16.x 结论&#xff1a; Navicat 导入sql文件&#xff0c;事务不会生效&#xff0c;无论怎么设置 mysql.exe 导入sql文件&#xff0c;事务生效 测试 准备一张表 name约束不能为空&#xff0c;用于测试事务失败…

SpringBoot 整合 Caffeine 实现本地缓存

目录 1、Caffeine 简介1.1、Caffeine 简介1.2、对比 Guava cache 的性能主要优化项1.3、常见的缓存淘汰算法1.4、SpringBoot 集成 Caffeine 两种方式 2、SpringBoot 集成 Caffeine 方式一2.1、缓存加载策略2.1.1、手动加载2.1.2、自动加载【Loading Cache】2.1.3、异步加载【As…

7、论等保的必要性

数据来源&#xff1a;7.论等保的必要性_哔哩哔哩_bilibili 等级保护必要性 降低信息安全风险 等级保护旨在降低信息安全风险&#xff0c;提高信息系统的安全防护能力。 风险发现与整改 开展等级保护的最重要原因是通过测评工作&#xff0c;发现单位系统内外部的安全风险和脆弱…