【CRASH】freelist异常导致的异常地址访问
freelist异常导致的异常地址访问
- 问题现象
- 初步分析
- 继续深入
- 新的发现
- 沙盘推演
- 寻找元凶
- 分析代码
- 后记
问题现象
项目一台设备几天内出现了两次crash,都是异常地址访问导致。
[66005.261660] BUG: unable to handle page fault for address: ffffff8881575110
初步分析
拿到coredump后,发现问题出在kmem_cache_cpu的freelist指针上。
crash> bt
PID: 4685 TASK: ffff88816f2b0000 CPU: 3 COMMAND: "mond"#0 [ffffc9000590f818] machine_kexec at ffffffff80284532#1 [ffffc9000590f898] __crash_kexec at ffffffff80383b82#2 [ffffc9000590f960] oops_end at ffffffff80248731#3 [ffffc9000590f980] page_fault_oops at ffffffff8028f0a6#4 [ffffc9000590f9a8] xas_create at ffffffff80f5272e#5 [ffffc9000590f9b0] brd_do_bvec at ffffffff809c9a60#6 [ffffc9000590fa08] kernelmode_fixup_or_oops at ffffffff8028f539#7 [ffffc9000590fa78] __bad_area_nosemaphore at ffffffff8028f9e3#8 [ffffc9000590faf8] exc_page_fault at ffffffff80f5adfc#9 [ffffc9000590fb20] asm_exc_page_fault at ffffffff81000b62[exception RIP: __kmem_cache_alloc_node+119]RIP: ffffffff80530257 RSP: ffffc9000590fbd0 RFLAGS: 00010246RAX: 0000000000000020 RBX: 0000000000000035 RCX: 0000000000000035RDX: 0000000001dfcf36 RSI: 0000000000000dc0 RDI: ffff888100041500RBP: ffffff88815750f0 R8: ffff888276dad410 R9: 0000000000000035R10: 0000000073646134 R11: 0000000004040404 R12: 00000000ffffffffR13: ffffffff80641477 R14: ffff888100041500 R15: 0000000000000dc0ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#10 [ffffc9000590fc00] __kmalloc at ffffffff804c9e77
#11 [ffffc9000590fc40] htree_dirblock_to_tree at ffffffff80641477
#12 [ffffc9000590fcc8] ext4_htree_fill_tree at ffffffff80640f75
#13 [ffffc9000590fdc8] ext4_readdir at ffffffff805f7c32
#14 [ffffc9000590fe88] iterate_dir at ffffffff80560d2b
#15 [ffffc9000590fed0] __x64_sys_getdents64 at ffffffff80561490
#16 [ffffc9000590ff28] do_syscall_64 at ffffffff80f57f28
#17 [ffffc9000590ff50] entry_SYSCALL_64_after_hwframe at ffffffff8100009bcrash> dis -l __kmem_cache_alloc_node+119
/code/FortiWEB/kernel/linux-6.1/mm/slub.c: 374 //获取内存ptr+offset位置保存的next空闲内存指针
0xffffffff80530257 <__kmem_cache_alloc_node+119>: mov 0x0(%rbp,%rax,1),%rbx
通过上面基本能推断出是freelist地址异常导致的这次问题。
为了使大家看的更清晰,也把汇编代码列出,关键过程加备注解释,方便理解:
crash> dis -r __kmem_cache_alloc_node+119
0xffffffff805301e0 <__kmem_cache_alloc_node>: nopl 0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffff805301e5 <__kmem_cache_alloc_node+5>: push %rbp
0xffffffff805301e6 <__kmem_cache_alloc_node+6>: push %r15
0xffffffff805301e8 <__kmem_cache_alloc_node+8>: push %r14
0xffffffff805301ea <__kmem_cache_alloc_node+10>: push %r13
0xffffffff805301ec <__kmem_cache_alloc_node+12>: push %r12
0xffffffff805301ee <__kmem_cache_alloc_node+14>: push %rbx
0xffffffff805301ef <__kmem_cache_alloc_node+15>: test %rdi,%rdi
0xffffffff805301f2 <__kmem_cache_alloc_node+18>: je 0xffffffff805302ae <__kmem_cache_alloc_node+206>
0xffffffff805301f8 <__kmem_cache_alloc_node+24>: mov %r8,%r13
0xffffffff805301fb <__kmem_cache_alloc_node+27>: mov %rcx,%r9
0xffffffff805301fe <__kmem_cache_alloc_node+30>: mov %edx,%r12d
0xffffffff80530201 <__kmem_cache_alloc_node+33>: mov %esi,%r15d
0xffffffff80530204 <__kmem_cache_alloc_node+36>: mov %rdi,%r14 //kmem_cache *s
0xffffffff80530207 <__kmem_cache_alloc_node+39>: cmpl $0x0,0x22f33f2(%rip) # 0xffffffff82823600 <kfence_allocation_key>
0xffffffff8053020e <__kmem_cache_alloc_node+46>: jle 0xffffffff8053021d <__kmem_cache_alloc_node+61>
0xffffffff80530210 <__kmem_cache_alloc_node+48>: cmpl $0x0,0x1a4da31(%rip) # 0xffffffff81f7dc48 <kfence_allocation_gate>
0xffffffff80530217 <__kmem_cache_alloc_node+55>: je 0xffffffff80530323 <__kmem_cache_alloc_node+323>
0xffffffff8053021d <__kmem_cache_alloc_node+61>: mov (%r14),%r8 //kmem_cache_cpu *cpu_slab
0xffffffff80530220 <__kmem_cache_alloc_node+64>: add %gs:0x7fae5360(%rip),%r8 # 0x15588
0xffffffff80530228 <__kmem_cache_alloc_node+72>: mov 0x8(%r8),%rdx
0xffffffff8053022c <__kmem_cache_alloc_node+76>: mov (%r8),%rbp //void **freelist
0xffffffff8053022f <__kmem_cache_alloc_node+79>: test %rbp,%rbp
0xffffffff80530232 <__kmem_cache_alloc_node+82>: je 0xffffffff805302be <__kmem_cache_alloc_node+222>
0xffffffff80530238 <__kmem_cache_alloc_node+88>: mov 0x10(%r8),%rax
0xffffffff8053023c <__kmem_cache_alloc_node+92>: test %rax,%rax
0xffffffff8053023f <__kmem_cache_alloc_node+95>: je 0xffffffff805302be <__kmem_cache_alloc_node+222>
0xffffffff80530241 <__kmem_cache_alloc_node+97>: cmp $0xffffffff,%r12d
0xffffffff80530245 <__kmem_cache_alloc_node+101>: je 0xffffffff80530253 <__kmem_cache_alloc_node+115>
0xffffffff80530247 <__kmem_cache_alloc_node+103>: mov (%rax),%rax
0xffffffff8053024a <__kmem_cache_alloc_node+106>: shr $0x3a,%rax
0xffffffff8053024e <__kmem_cache_alloc_node+110>: cmp %r12d,%eax
0xffffffff80530251 <__kmem_cache_alloc_node+113>: jne 0xffffffff805302be <__kmem_cache_alloc_node+222>
0xffffffff80530253 <__kmem_cache_alloc_node+115>: mov 0x28(%r14),%eax //offset
0xffffffff80530257 <__kmem_cache_alloc_node+119>: mov 0x0(%rbp,%rax,1),%rbx //*(freelist + offset) 获取内存ptr+offset位置保存的next空闲内存指针
R14=RDI=(struct kmem_cache *)ffff888100041500
RAX=offset=0x20
RBP=freelist=ffffff88815750f0
为了严谨,通过kmem_cache确认一下。
struct kmem_cache {cpu_slab = 0x2d410,flags = 0x40001000,min_partial = 0x5,size = 0x40,object_size = 0x40,reciprocal_size = {m = 0x1,sh1 = 0x1,sh2 = 0x5},offset = 0x20, //RAXcpu_partial = 0x78,cpu_partial_slabs = 0x4,oo = {x = 0x40},min = {x = 0x40},allocflags = 0x0,refcount = 0x1,ctor = 0x0,inuse = 0x40,align = 0x40,red_left_pad = 0x0,name = 0xffffffff81582d0a "kmalloc-64", //通用的64字节的slab分配器crash> kmem_cache_cpu 0x2d410:3 //在问题CPU3上的 cpu_slab
[3]: ffff888276dad410
struct kmem_cache_cpu {freelist = 0xffffff88815750f0, //RBP 问题freelisttid = 31444790,slab = 0xffffea00055d43c0,partial = 0xffffea000400fac0,lock = {<No data fields>}
}
也就是说 通用slab分配器 kmalloc-64在CPU3上的freelist异常,导致新申请内存时因为无法访问freelist+offset去获取下一个空闲object内存指针,导致了系统crash。
继续深入
接下来到比较头疼的地方了。freelist是怎么异常的?
是内核或者模块中有kfree(ptr=0xffffff88815750f0)将这个指针放回到freelist上的么?
答案是否定的!因为kfree释放地址时,slab会将原 freelist指针写到 ptr+kmem_cache.offset位置。而ptr=0xffffff88815750f0 是不可访问的地址,在kfree时就会出发地址访问异常。
我们再次审视 0xffffff88815750f0 这个异常地址,发现它比较怪异。它更像是一个正常地址的偏移。
从kmem_cache_cpu.slab我们可以知道slab对应的内存范围 ffff88815750f000 ~ ffff88815750ffff。
crash> kmem 0xffffea00055d43c0
CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME
kmem: kmalloc-64: slab: ffffea00055d43c0 invalid freepointer: ffffff8881575110
ffff888100041500 64 4063 4608 72 4k kmalloc-64SLAB MEMORY NODE TOTAL ALLOCATED FREE
kmem: kmalloc-64: slab: ffffea00055d43c0 invalid freepointer: ffffff8881575110ffffea00055d43c0 ffff88815750f000 0 64 63 1FREE / [ALLOCATED]
kmem: kmalloc-64: slab: ffffea00055d43c0 invalid freepointer: ffffff8881575110PAGE PHYSICAL MAPPING INDEX CNT FLAGS
ffffea00055d43c0 15750f000 ffff888100041500 0 1 200000000000200 slab
slab对应地址 ff ff 88 81 57 50 f0 00
异常freelist ff ff ff 88 81 57 50 f0
感觉像是 一个正常地址存在内存中,读取时偏移了一个字节。
00 f0 50 57 81 88 ff ff ff
0 1 2 3 4 5 6 7 8
从0-7 就是 ffff88815750f000 , 从1到8 就是 ffffff88815750f0。
新的发现
异常内存地址的特点,基本指向了use_after_free,也就是说内存归还给slab分配器后,又对内存进行操作,导致异常。
但是如何推演出问题场景,还没有好的思路。另外kmalloc-64是通用的分配器,可能各种地方都在使用,一时不好去怀疑是哪个地方可能出了问题。
由于工作上同时有多个bug要处理,暂时搁置了下。然后QA报告该设备又出现一次crash,现象有些不同。
crash> bt
PID: 31715 TASK: ffff888106ef2e80 CPU: 2 COMMAND: "mond"#0 [ffffc90004f1f908] machine_kexec at ffffffff80284532#1 [ffffc90004f1f980] __crash_kexec at ffffffff80383b82#2 [ffffc90004f1fa48] oops_end at ffffffff80248731#3 [ffffc90004f1fa68] exc_general_protection at ffffffff80f588dd#4 [ffffc90004f1fb90] asm_exc_general_protection at ffffffff81000aa2[exception RIP: rb_insert_color+75]RIP: ffffffff80f4638b RSP: ffffc90004f1fc40 RFLAGS: 00010246RAX: ffff8881018bfdd0 RBX: 0000000000000005 RCX: ff88810242fd093aRDX: ffff8881274abe48 RSI: ffff88810242fa80 RDI: ffff888141437f88RBP: ffff88810242f0c8 R8: ffff88810242fd88 R9: ffff8881274ab180R10: 0000000070747962 R11: 0000000005050505 R12: ffff8881274ab180R13: 00000000454ccceb R14: 000000000d8620ac R15: ffff88817a984a60ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018#5 [ffffc90004f1fc40] htree_dirblock_to_tree at ffffffff80641531#6 [ffffc90004f1fcc8] ext4_htree_fill_tree at ffffffff80640f75#7 [ffffc90004f1fdc8] ext4_readdir at ffffffff805f7c32#8 [ffffc90004f1fe88] iterate_dir at ffffffff80560d2b#9 [ffffc90004f1fed0] __x64_sys_getdents64 at ffffffff80561490
#10 [ffffc90004f1ff28] do_syscall_64 at ffffffff80f57f28
#11 [ffffc90004f1ff50] entry_SYSCALL_64_after_hwframe at ffffffff8100009b
这次是出在红黑树的插入时。巧的是错误地址 ff88810242fd093a 也像是读取发生偏移导致。
crash> dis -l rb_insert_color+75
/code/FortiWEB/kernel/linux-6.1/lib/rbtree.c: 115
0xffffffff80f4638b <rb_insert_color+75>: mov 0x8(%rcx),%rdxcrash> dis -r rb_insert_color+75
0xffffffff80f46340 <rb_insert_color>: mov (%rdi),%r8
0xffffffff80f46343 <rb_insert_color+3>: test %r8,%r8
0xffffffff80f46346 <rb_insert_color+6>: jne 0xffffffff80f4637f <rb_insert_color+63>
0xffffffff80f46348 <rb_insert_color+8>: mov %rdi,%rcx
0xffffffff80f4634b <rb_insert_color+11>: movq $0x1,(%rcx)
0xffffffff80f46352 <rb_insert_color+18>: ret
0xffffffff80f46353 <rb_insert_color+19>: nopw %cs:0x0(%rax,%rax,1)
0xffffffff80f4635d <rb_insert_color+29>: nopl (%rax)
0xffffffff80f46360 <rb_insert_color+32>: mov %rcx,%rax
0xffffffff80f46363 <rb_insert_color+35>: or $0x1,%rax
0xffffffff80f46367 <rb_insert_color+39>: mov %rax,(%rdx)
0xffffffff80f4636a <rb_insert_color+42>: mov %rax,(%r8)
0xffffffff80f4636d <rb_insert_color+45>: mov (%rcx),%r8
0xffffffff80f46370 <rb_insert_color+48>: and $0xfffffffffffffffc,%r8
0xffffffff80f46374 <rb_insert_color+52>: mov %r8,(%rcx)
0xffffffff80f46377 <rb_insert_color+55>: mov %rcx,%rdi
0xffffffff80f4637a <rb_insert_color+58>: test %r8,%r8
0xffffffff80f4637d <rb_insert_color+61>: je 0xffffffff80f4634b <rb_insert_color+11>
0xffffffff80f4637f <rb_insert_color+63>: mov (%r8),%rcx
0xffffffff80f46382 <rb_insert_color+66>: test $0x1,%cl
0xffffffff80f46385 <rb_insert_color+69>: jne 0xffffffff80f4649f <rb_insert_color+351>
0xffffffff80f4638b <rb_insert_color+75>: mov 0x8(%rcx),%rdx
通过反汇编,找到红黑树的根节点。
crash> dir_private_info.root 0xffff88810242fa80 root = {rb_node = 0xffff88810242f688},crash> fname -x ffff88810242fd80
struct fname {hash = 0xb2f52600,minor_hash = 0x32115811,rb_hash = {__rb_parent_color = 0xff88810242fd093a, //这里就是异常发生的地址rb_right = 0xffff888141437f88,rb_left = 0xff88810242f0c8ff //异常},next = 0xff, //明显异常inode = 0x7a5900,name_len = 0x0,file_type = 0x5,name = 0xffff88810242fdae "\003ttyac" //明显异常
}
然后试着将ffff88810242fd80 偏移1个字节,再按fname结构去读取
crash> fname -x ffff88810242fd81
struct fname {hash = 0x11b2f526,minor_hash = 0x3a321158,rb_hash = {__rb_parent_color = 0x88ff88810242fd09,rb_right = 0xffffff888141437f,rb_left = 0xffff88810242f0c8},next = 0x0,inode = 0x7a59,name_len = 0x5,file_type = 0x3,name = 0xffff88810242fdaf "ttyac"
}
推断是申请fname时返回的是 ffff88810242fd81, 而在红黑树操作和旋转时,又以ffff88810242fd80去访问(最低位的1bit被当作红黑树的着色而或掉了)。
kmalloc时返回ffff88810242fd81,表明有use_after_free将 freelist+offset里的地址ffff88810242fd80改为了ffff88810242fd81。
要想满足这个并不容易,因为普通的覆写会整个破坏。像这种只改一个bit的,一般有两种情况:
- atomic_inc
- set_bit
也就是说存在一个结构,偏移0x20的位置是一个atomic或flags变量。当内存free后,这里保存的时next free object的地址指针。此时对这个结构加偏移位置内存的atomic_inc或set_bit,导致next free object地址指针的改变。此时kmalloc申请到的内存指针就会是正常指针ptr偏移1byte。
沙盘推演
kmallo获取地址偏移1byte的原因理清楚了。那么最早的 这个异常freelist = ffffff88815750f0 是怎么来的呢?
聪明的读者可能一下子就明白了。不明白的没关系,我也是又想了好久才弄清晰的。
答案就是next free的next free。
freelist--| |-----正确next----| 正确地址 v | v v---------------A--------------- -------------------B---------------------| |偏移1个byte| | |00| |00|f0|50|57|81|88|ff|ff|ff| |------------------------------- -----------------------------------------| ^ ^|-----错误next-------| 错误地址
正常情况下freelist+offset位置存储着下一个free object的地址, 而free object+offset位置存储着下下一个free object的地址。
- 异常use_after_free, 修改了object A内存的 offset位置,导致此位置存储的next指针偏移。
- kmalloc申请内存,返回object A的地址。此时freelist=*(freelist + offset)位置得到错误的next object(向右偏移了一个byte)。
- kmalloc申请内存,返回object B+1的地址。一般为freelist向右偏移了1个byte,所以读取到的地址就会变成ffffff88815750f0 。
寻找元凶
思路通透以后,就是寻找元凶的时刻了。
kmalloc-64太通用了,不像其他特定的slab分配器,从代码上是不好定位的。
只能通过查看内存进行分析,好在这个分配器一个slab page包含64个object,不算很多。
比较幸运的是object中都留有有效信息,迅速帮我们找到内存的使用(或曾经使用)者。
crash> rd -s ffff88810bac50c0 8
ffff88810bac50c0: 0000000000000000 broad_proc_cleanup+10752
ffff88810bac50d0: ffff888101db68e8 ffff888101db68e8
ffff88810bac50e0: 0000000000000001 0000000000000000
ffff88810bac50f0: 0000000000000000 0000000000000000
//通过broad_proc_cleanup 找到这是个 team_item
crash> groups_item ffff88810bac50c0(4)
struct groups_item {hnode = {next = 0x0,pprev = 0xffffffffa03b1130 <borad_proc_cleanup+10752>},glist = {next = 0xffff888101db68e8,prev = 0xffff888101db68e8},list_account = {counter = 1 //atomic_t变量}
}
这是一个业务模块,巧的是 list_account就是个atomic变量
基本上可以怀疑是这个业务模块对结构的user_after_free导致的。
为了全面,干脆把剩下的也看了。
crash> rd -s ffff88810bac5240 8
ffff88810bac5240: 0000000000000000 ffffc900098dc000
ffff88810bac5250: 0000000000005000 0000000000000002
ffff88810bac5260: ffff8881457d6de0 0000000400000000
ffff88810bac5270: 0000000000000000 copy_process+395 //通过copy_process找到这是个 vm_struct
crash> vm_struct ffff88810bac5240(10)
struct vm_struct {next = 0x0,addr = 0xffffc900098dc000,size = 20480,flags = 2,pages = 0xffff8881457d6de0,page_order = 0,nr_pages = 4,phys_addr = 0,caller = 0xffffffff8029cdab <copy_process+395>
}
经过筛选,这个slab page 只有 fname,vm_struct和team_item在使用。
fname和vm_struct是内核代码, 出问题概率非常低,基本就是 业务模块了。
根据之前推导,应该是业务模块在释放 team_item后,又对其进行了 atomic_inc操作导致。
分析代码
找到元凶后,就剩下分析模块代码,找到出问题点。
代码问题比较隐蔽,初看没有问题。再仔细分析时,发现存在并发问题。
读写锁对事务的保护不够完善,查找和操作并没有完全保护起来,而是分成两部分保护了。
后记
因为是总结,所以条理相对清晰有序。实际分析这个问题是遇到不少困难,也走了一些弯路。一度有点沮丧,感觉找不到思路。还好最终找到问题原因。
其中也有一些幸运的地方,比如内存中留下了蛛丝马迹,帮助了解内存用途,如果没有这些,定位难度会大大提高。
相关文章:

【CRASH】freelist异常导致的异常地址访问
freelist异常导致的异常地址访问 问题现象初步分析继续深入新的发现沙盘推演寻找元凶分析代码后记 问题现象 项目一台设备几天内出现了两次crash,都是异常地址访问导致。 [66005.261660] BUG: unable to handle page fault for address: ffffff8881575110初步分析…...
【QT】C++ || 左值引用、右值引用、移动语义、完美转发
在C中,左右值引用是高级语言特性,用于更高效的内存和资源管理。了解左右值引用的概念对于编写高效的C代码非常重要。下面解释左右值引用的概念、用途和区别,并通过示例来说明它们的使用。 左值引用(Lvalue Reference)…...

【深度学习驱动流体力学】计算流体力学算例剖析与实现
目录 一.求解器分类汇总压缩性流动求解器(Compressible Flow Solvers):不可压缩流动求解器(Incompressible Flow Solvers):多相流动求解器(Multiphase Flow Solvers):热传递求解器(Heat Transfer Solvers):其他特殊求解器:其他常见求解器:求解器分类:二.求解器案…...

Midjourney角色一致性如何控制两个人物
实操演示 如何用Midjourney完成《甄嬛大战蝙蝠侠》 思路 先生成一个大致符合要求的图片,作为底图基于底图,用局部重绘功能,逐步修改细节 生成底图 我们想要甄嬛大战蝙蝠侠,先试一下直接让他生成 Zhen Huan vs. Batman, in t…...

Python基础-引用参数、斐波那契数列、无极分类
1.引用参数的问题 (1)列表(list) 引用参数,传地址的参数,即list1会因list2修改而改变。 list1 [1,2,3,4] list2 list1 print(list1) list2[2] 1 print(list2) print(list1)非引用参数,不传…...

【MySQL统计函数count详解】
MySQL统计函数count详解 1. count()概述2. count(1)和count(*)和count(列名)的区别3. count(*)的实现方式 1. count()概述 count() 是一个聚合函数,返回指定匹配条件的行数。开发中常用来统计表中数据,全部数据,不为null数据,或…...

大数据的发展,带动电子商务产业链,促进了社会的进步【电商数据采集API接口推动电商项目的源动力】
最近几年计算机技术在诸多领域得到了有效的应用,同时在多方面深刻影响着我国经济水平的发展。除此之外,人民群众的日常生活水平也受大数据技术的影响。 在这其中电子商务领域也在大数据技术的支持下,得到了明显的进步。虽然电子商务领域的发…...
Python类中变量定义详解
✨前言: Python中的类可以定义两种类型的变量:类变量和实例变量。 类变量(Class Variables): 类变量是在类级别上定义的变量,它们是对所有实例共享的。这意味着类变量只有一个副本,无论你创建了…...
c++ extern 关键字详解
extern关键字在C中用于声明变量或函数的外部链接。它通常用于以下几种场景: 声明全局变量:在一个文件中定义变量,在其他文件中使用extern声明该变量,以便在多个文件之间共享。C和C混合编程:在C代码中引用C语言编写的函…...

计算机网络:运输层 - TCP 流量控制 拥塞控制
计算机网络:运输层 - TCP 流量控制 & 拥塞控制 滑动窗口流量控制拥塞控制慢开始算法拥塞避免算法快重传算法快恢复算法 滑动窗口 如图所示: 在TCP首部中有一个窗口字段,该字段就基于滑动窗口来辅助流量控制和拥塞控制。所以我们先讲解滑…...

Python学习打卡:day10
day10 笔记来源于:黑马程序员python教程,8天python从入门到精通,学python看这套就够了 目录 day1073、文件的读取操作文件的操作步骤open()打开函数mode常用的三种基础访问模式读操作相关方法read()方法readlines()方法readline()方法for循…...

新书速览|Ubuntu Linux运维从零开始学
《Ubuntu Linux运维从零开始学》 本书内容 Ubuntu Linux是目前最流行的Linux操作系统之一。Ubuntu的目标在于为一般用户提供一个最新的、相当稳定的、主要由自由软件构建而成的操作系统。Ubuntu具有庞大的社区力量,用户可以方便地从社区获得帮助。《Ubuntu Linux运…...

[Qt的学习日常]--窗口
前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、窗口的分…...

Vue发送http请求
1.创建项目 创建一个新的 Vue 2 项目非常简单。在终端中,进入您希望创建项目的目录(我的目录是D:\vue),并运行以下命令: vue create vue_test 2.切换到项目目录,运行项目 运行成功后,你将会看到以下的编译成功的提示…...

学习使用js和jquery修改css路径,实现html页面主题切换功能
学习使用js和jquery修改css路径,实现html页面主题切换功能 效果图html代码js切换css关键代码jquery切换css关键代码 效果图 html代码 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>修改css路径</title&g…...
(转)请介绍一下Redis的数据淘汰策略
1. **NoEviction(不淘汰)**:当内存不足时,直接返回错误,不淘汰任何数据。该策略适用于禁止数据淘汰的场景,但需要保证内存足够。 2. **AllKeysLFU(最少使用次数淘汰)**:…...

APP自动化测试-Appium常见操作之详讲
一、基本操作 1、点击操作 示例:element.click() 针对元素进行点击操作 2、初始化:输入中文的处理 说明:如果连接的是虚拟机(真机无需加这两个参数,加上可能会影响手工输入),在初始化配置中…...

写给大数据开发:谈谈数仓建模的反三范式
在数仓建设中,我们经常谈论反三范式。顾名思义,反范式化指的是通过增加冗余或重复的数据来提高数据库的读性能。简单来说,就是浪费存储空间,节省查询时间。用行话讲,这就是以空间换时间。听起来像是用大炮打蚊子&#…...

Stable diffusion 3 正式开源
6月12日晚,著名开源大模型平台Stability AI正式开源了,文生图片模型Stable Diffusion 3 Medium(以下简称“SD3-M”)权重。 SD3-M有20亿参数,平均生成图片时间在2—10秒左右推理效率非常高,同时对硬件的需求…...

如何配置node.js环境
文章目录 step1. 下载node.js安装包step2. 创建node_global, node_cache文件夹step3.配置node环境变量step3. cmd窗口检查安装的node和npm版本号step4. 设置缓存路径\全局安装路径\下载镜像step5. 测试配置的nodejs环境 step1. 下载node.js安装包 下载地址:node.js…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...