一个panic问题引起对percpu变量的思考

news2024/9/25 1:23:35

1 问题引入

最近在分析一个panic问题时,发现panic现场无法与log对应起来。

先贴log:

<1>[  180.089084] Unable to handle kernel NULL pointer dereference at virtual address 00000001
<1>[  180.099551] pgd = 8bbde651
<1>[  180.107775] Unable to handle kernel NULL pointer dereference at virtual address 00000001
<1>[  180.108527] [00000001] *pgd=45636835, *pte=00000000, *ppte=00000000
<1>[  180.121525] pgd = 8bbde651
<1>[  180.135901] [00000001] *pgd=45636835, *pte=00000000, *ppte=00000000
<0>[  180.136405] Internal error: Oops: 17 [#1] PREEMPT SMP THUMB2
<0>[  180.147836] Modules linked in: cw221x(O) dwc3 sdhci_axera dwc3_axera spi_axera_module [last unloaded: kspi]
<0>[  180.157597] CPU: 1 PID: 124 Comm: qs_sleep Tainted: G           O      4.19.125 #2
<0>[  180.165167] Hardware name: Axera_chip (Device Tree)
<0>[  180.170059] PC is at kmem_cache_alloc+0x80/0xd4
<0>[  180.174592] LR is at kmem_cache_alloc+0x15/0xd4
<0>[  180.179124] pc : [<c0084f50>]    lr : [<c0084ee5>]    psr: 60000033
<0>[  180.185393] sp : c56cfde0  ip : c5bda108  fp : 00000000
<0>[  180.190619] r10: 00000000  r9 : c5c6b420  r8 : 0001ed1c
<0>[  180.195845] r7 : ffffe000  r6 : c00c29fd  r5 : 006000c0  r4 : c6001e40
<0>[  180.202374] r3 : 00000001  r2 : 00000000  r1 : 0001ed1c  r0 : 00000000
<0>[  180.208906] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA Thumb  Segment user
<0>[  180.216217] Control: 50c5383d  Table: 45bc806a  DAC: 00000055
<0>[  180.221967] Process qs_sleep (pid: 124, stack limit = 0x51827165)
<0>[  180.228063] Stack: (0xc56cfde0 to 0xc56d0000)
<0>[  180.232425] fde0: c049f8fc c53bc980 00000000 c612bd80 c0372ac8 c55fbe40 c5c6b420 c00c29fd
<0>[  180.240608] fe00: c5c6b420 c049f8fc 00000000 c55fbe40 00000000 c5c6b500 c5c6b420 c00c285f
<0>[  180.248790] fe20: c55fbe48 00000000 00000000 c0087393 c5c79a18 c56cfed0 00000000 c55fbe40
<0>[  180.256973] fe40: c5c6b420 00000000 00000000 c0092759 c5b81978 00000001 c56cff74 00000002
<0>[  180.265156] fe60: 00000000 00000041 c5c79908 000041ed 00000000 00000006 00000000 c56cfed8
<0>[  180.273338] fe80: 00000000 ffffe000 c6094400 00000000 c5c6b420 c5b96610 c5c79a18 00010001
<0>[  180.281520] fea0: c56cfea0 c56cfea0 0000001d 00000033 c56cff74 00000001 c6247000 c00091e4
<0>[  180.289703] fec0: c56ce000 00000005 0000000a c009285b c5b96610 c5c79a18 7d11879d 00000009
<0>[  180.297886] fee0: c624701b c025690d c6006e10 c5c02aa0 c5c6b420 00000101 00000000 00000048
<0>[  180.306069] ff00: 00000000 00000000 00000000 c56cff10 c043feb3 c048d5de c05882c0 c61d89c8
<0>[  180.314251] ff20: c043feb3 00000033 c5123a00 c5b96f00 c5b96f40 c036611f 00000000 c009ac05
<0>[  180.322434] ff40: c6247000 00000000 00000002 00000002 ffffff9c c00091e4 00000033 00000002
<0>[  180.330616] ff60: ffffff9c c0087f57 00000000 00000000 c61d89c1 00000002 00000000 00000006
<0>[  180.338797] ff80: 00000100 00000001 00000000 00000000 00000002 b67bbda8 00000005 c00091e4
<0>[  180.346979] ffa0: c56ce000 c0009001 00000000 00000002 007c4ff8 00000002 00000000 00000001
<0>[  180.355161] ffc0: 00000000 00000002 b67bbda8 00000005 00000005 005228ac 00000032 0000000a
<0>[  180.363343] ffe0: 00000000 b67bbda8 b6dcfe33 b6dcfe46 80000030 007c4ff8 00000000 00000000
<0>[  180.371542] [<c0084f50>] (kmem_cache_alloc) from [<c00c29fd>] (kernfs_fop_open+0x19f/0x23a)
<0>[  180.379902] [<c00c29fd>] (kernfs_fop_open) from [<c0087393>] (do_dentry_open+0x1f3/0x260)
<0>[  180.388088] [<c0087393>] (do_dentry_open) from [<c0092759>] (path_openat+0x7d7/0x8ba)
<0>[  180.395927] [<c0092759>] (path_openat) from [<c009285b>] (do_filp_open+0x1f/0x50)
<0>[  180.403416] [<c009285b>] (do_filp_open) from [<c0087f57>] (do_sys_open+0xd3/0x140)
<0>[  180.410993] [<c0087f57>] (do_sys_open) from [<c0009001>] (ret_fast_syscall+0x1/0x5a)
<0>[  180.418737] Exception stack(0xc56cffa8 to 0xc56cfff0)
<0>[  180.423792] ffa0:                   00000000 00000002 007c4ff8 00000002 00000000 00000001
<0>[  180.431973] ffc0: 00000000 00000002 b67bbda8 00000005 00000005 005228ac 00000032 0000000a
<0>[  180.440153] ffe0: 00000000 b67bbda8 b6dcfe33 b6dcfe46
<0>[  180.445211] Code: 4618 e8bd 83f8 6962 (f853) e002
<0>[  180.450008] Internal error: Oops: 17 [#2] PREEMPT SMP THUMB2
<0>[  180.455673] Modules linked in: cw221x(O) dwc3 sdhci_axera dwc3_axera spi_axera_module [last unloaded: kspi]
<4>[  180.456034] ---[ end trace 4fe5cd369560c84c ]---
<0>[  180.465435] CPU: 0 PID: 165 Comm: encoder Tainted: G      D    O      4.19.125 #2
<0>[  180.465438] Hardware name: Axera_chip (Device Tree)
<0>[  180.465455] PC is at kmem_cache_alloc+0x80/0xd4
<0>[  180.465461] LR is at kmem_cache_alloc+0x15/0xd4
<0>[  180.465465] pc : [<c0084f50>]    lr : [<c0084ee5>]    psr: 60000033
<0>[  180.465470] sp : c53bfe68  ip : 60000013  fp : 00000000
<0>[  180.465474] r10: c55fb840  r9 : 00001000  r8 : 0001ed24
<0>[  180.465479] r7 : ffffe000  r6 : c00fd299  r5 : 006000c0  r4 : c6001e40
<0>[  180.465484] r3 : 00000001  r2 : 00000000  r1 : 0001ed24  r0 : 00000000
<0>[  180.465489] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA Thumb  Segment user
<0>[  180.465494] Control: 50c5383d  Table: 45bc806a  DAC: 00000055
<0>[  180.465501] Process encoder (pid: 165, stack limit = 0xb65c0d9e)
<0>[  180.465506] Stack: (0xc53bfe68 to 0xc53c0000)
<0>[  180.465514] fe60:                   c049f8fc 00000000 00000000 c5bda120 c5bda108 00fa24a0
<0>[  180.465522] fe80: 00001000 c00fd299 c00fd44d c5bda108 c5bda108 c5bda120 00000000 c00fd457
<0>[  180.470413] Kernel panic - not syncing: Fatal exception
<0>[  180.477620] fea0: c5bda108 c53bff88 00000000 c009e7c7 c5bda120 c5bda138 c6246000 c00091e4
<0>[  180.574453] fec0: c53be000 c62b8080 c009e70f 00000001 00000000 00001000 c53bff88 00000003
<0>[  180.582636] fee0: 00000000 c00b8a55 c53bff88 c55fb840 c036ff00 c00b8a17 c53bff88 c0089839
<0>[  180.590818] ff00: 00000000 00000000 00000001 c00ae3f1 c00b8901 b26e0d7c c5c6e028 c55fb840
<0>[  180.599000] ff20: 00000034 c0093ac9 0000541b c009402f 00000000 00000000 00000000 c55fb840
<0>[  180.607183] ff40: c55fb843 00001000 c55fb840 00000000 00001000 00000001 00fa24a0 c0089939
<0>[  180.615366] ff60: c55fb840 00fa24a0 00001000 c55fb840 c55fb843 00fa24a0 00001000 c00091e4
<0>[  180.623549] ff80: c53be000 c0089c71 00000000 00000000 00001000 00000034 00000000 b26e0d88
<0>[  180.631732] ffa0: 00000003 c0009001 00000034 00000000 00000034 00fa24a0 00001000 00000003
<0>[  180.639915] ffc0: 00000034 00000000 b26e0d88 00000003 b26e0ea4 004034ac be96d69c 00000000
<0>[  180.648097] ffe0: 0080761c b26e0d88 b6dd155f b6dd1516 00000030 00000034 00000000 00000000
<0>[  180.656293] [<c0084f50>] (kmem_cache_alloc) from [<c00fd299>] (disk_seqf_start+0x13/0x5a)
<0>[  180.664480] [<c00fd299>] (disk_seqf_start) from [<c00fd457>] (show_partition_start+0xb/0x2c)
<0>[  180.672928] [<c00fd457>] (show_partition_start) from [<c009e7c7>] (seq_read+0xb9/0x27a)
<0>[  180.680942] [<c009e7c7>] (seq_read) from [<c00b8a55>] (proc_reg_read+0x3f/0x5e)
<0>[  180.688261] [<c00b8a55>] (proc_reg_read) from [<c0089839>] (__vfs_read+0x15/0xc2)
<0>[  180.695751] [<c0089839>] (__vfs_read) from [<c0089939>] (vfs_read+0x53/0xb6)
<0>[  180.702806] [<c0089939>] (vfs_read) from [<c0089c71>] (ksys_read+0x2d/0x64)
<0>[  180.709775] [<c0089c71>] (ksys_read) from [<c0009001>] (ret_fast_syscall+0x1/0x5a)
<0>[  180.717346] Exception stack(0xc53bffa8 to 0xc53bfff0)
<0>[  180.722401] ffa0:                   00000034 00000000 00000034 00fa24a0 00001000 00000003
<0>[  180.730583] ffc0: 00000034 00000000 b26e0d88 00000003 b26e0ea4 004034ac be96d69c 00000000
<0>[  180.738764] ffe0: 0080761c b26e0d88 b6dd155f b6dd1516
<0>[  180.743822] Code: 4618 e8bd 83f8 6962 (f853) e002
<2>[  180.748618] CPU0: stopping

Log中CPU 0和CPU 1均发生了,出错误的位置均是:kmem_cache_alloc+0x80,对应的汇编:

ZST:0076::C0084F50|F853E002 ldr r14,[r3,r2]

CPU 1寄存器值:
<0>[  180.202374] r3 : 00000001  r2 : 00000000  r1 : 0001ed1c  r0 : 00000000 

CPU 0寄存器值:

<0>[  180.465484] r3 : 00000001  r2 : 00000000  r1 : 0001ed24  r0 : 00000000

r2、r3寄存器值一致,从r3+r2地址加载数据到r14, r3+r2=0x1,访问了0x1地址,这与log:

Unable to handle kernel NULL pointer dereference at virtual address 00000001

能对应上。

接下来分析出错时的函数调用栈:

-000|freelist_dereference(inline)
-000|get_freepointer(inline)
-000|get_freepointer_safe(inline)
-000|slab_alloc_node(inline)
    |  object = 0x1
-000|slab_alloc(inline)
-000|kmem_cache_alloc(s = 0xC6001E40, gfpflags = 6291648)
    |  s = 0xC6001E40
    |  gfpflags = 6291648
-001|kmalloc(inline)
-001|kernfs_get_open_node(inline)
    |  on = 0x0
    |  new_on = 0x0
-001|kernfs_fop_open(inode = 0xC5C6B420, file = 0xC55FBE40)
    |  inode = 0xC5C6B420
    |  file = 0xC55FBE40
    |  kn = 0xC612BD80
    |  __key = ()
    |  __key = ()
    |  __key = ()
-002|do_dentry_open(f = 0xC55FBE40, inode = 0xC5C6B420, open = 0xC00C285F)
    |  f = 0xC55FBE40
    |  inode = 0xC5C6B420
    |  open = 0xC00C285F
    |  empty_fops = (owner = 0x0, llseek = 0x0, read = 0x0, write = 0x0, read_iter = 0x0, write_iter = 0x0, iterate = 0x0, iterate_shared = 0x0, poll = 0x0, unlocked_ioctl = 0x0, compat_ioctl = 0x0, mmap = 0x0, mmap_supported_flags = 0, open = 0x0, flush = 0x0, release = 0x0, fsync = 0x0, fasync = 0x0, lock = 0x0, sendpage = 0x0, get_unmapped_area = 0x0, check_flags = 0x0, flock = 0x0, splice_write = 0x0, splice_read = 0x0, setlease = 0x0, fallocate = 0x0, show_fdinfo = 0x0, copy_file_range = 0x0, clone_file_range = 0x0, dedupe_file_range = 0x0, fadvise = 0x0)
    |  error = 0
    |  __warned = FALSE
-002|vfs_open(tailcall)
-003|do_last(inline)
    |  will_truncate = FALSE
    |  got_write = FALSE
    |  seq = 0
    |  inode = 0xC5C6B420
    |  path = (mnt = 0xC5B96610, dentry = 0xC5C79A18)
-003|path_openat(nd = 0xC56CFED0, op = ?, flags = ?)
    |  nd = 0xC56CFED0
    |  file = 0xC55FBE40
    |  error = 0
-004|do_filp_open(dfd = ?, pathname = ?, op = 0xC56CFF74)
    |  op = 0xC56CFF74
    |  nd = (path = (mnt = 0xC5B96610, dentry = 0xC5C79A18), last = (hash = 2098300829, len = 9, hash_len = 40753006493, name = 0xC624701B), root = (mnt = 0xC6006E10, dentry = 0xC5C02AA0), inode = 0xC5C6B420, flags = 257, seq = 0, m_seq = 72, last_type = 0, depth = 0, total_link_count = 0, stack = 0xC56CFF10, internal = ((link = (mnt = 0xC043FEB3, dentry = 0xC048D5DE), done = (fn = 0xC05882C0, arg = 0xC61D89C8), name = 0xC043FEB3, seq = 51), (link = (mnt = 0xC5123A00, dentry = 0xC5B96F00), done = (fn = 0xC5B96F40, arg = 0xC036611F), name = 0x0, seq = 3221859333)), name = 0xC6247000, saved = 0x0, link_inode = 0x2, root_seq = 2, dfd = -100)
    |  flags = 1
    |  filp = 0x33
-005|do_sys_open(dfd = -100, filename = ?, flags = 2, mode = ?)
    |  dfd = -100
    |  flags = 2
    |  op = (open_flag = 2, mode = 0, acc_mode = 6, intent = 256, lookup_flags = 1)
    |  fd = 51
    |  tmp = 0xC6247000
    |  f = ???
-006|__entry_text_start(asm)
 ---|end of frame

通过分析发现,kmalloc函数中调用kmem_cache_alloc_trace是一个关键突破口:

static __always_inline void *kmalloc(size_t size, gfp_t flags)
{
	if (__builtin_constant_p(size)) {
		if (size > KMALLOC_MAX_CACHE_SIZE)
			return kmalloc_large(size, flags);
#ifndef CONFIG_SLOB
		if (!(flags & GFP_DMA)) {
			unsigned int index = kmalloc_index(size);

			if (!index)
				return ZERO_SIZE_PTR;

			return kmem_cache_alloc_trace(kmalloc_caches[index],
					flags, size);
		}
#endif
	}
	return __kmalloc(size, flags);
}

在第13行:kmem_cache_alloc_trace(kmalloc_caches[index],可知传递给kmem_cache_alloc_trace函数的第一个参数是kmalloc_caches[index],根据调用栈的第8行:

s = 0xC6001E40,查看kmalloc_caches数组值:

  kmalloc_caches = (
    0x0,
    0x0,
    0xC6001CC0,
    0x0,
    0x0,
    0x0,
    0xC6001E40,
    0xC6001D80,
    0xC6001C00,
    0xC6001B40,
    0xC6001A80,
    0xC60019C0,
    0xC6001900,
    0xC6001840)

可知,index=6,对应kmalloc申请的size为2^6=64字节。

再回到PC指针位置,对应出错的代码应该是第2683行:


这里object的取到的object值为0x1, 而object的值是在第2677行获取到的,而c值是通过第2656行:

c = raw_cpu_ptr(s->cpu_slab);

获取到的,那么object实际就是kmalloc_caches[6].cpu_slab->freelist,但查看kmalloc_caches[6].cpu_slab->freelist的值为0,并不是1:

  kmalloc_caches = (
    0x0,
    0x0,
    0xC6001CC0,
    0x0,
    0x0,
    0x0,
    0xC6001E40 -> (
      cpu_slab = 0xC0530BF0 -> (
        freelist_=_0x0,
        tid = 0,
        page = 0x0),
      flags = 0,

2 问题出在哪里

注意到kmalloc_caches数组的类型为:struct kmem_cache,其定义如下:

struct kmem_cache {
	struct kmem_cache_cpu __percpu *cpu_slab;
	/* Used for retriving partial slabs etc */
	slab_flags_t flags;
	unsigned long min_partial;
	unsigned int size;	/* The size of an object including meta data */
	unsigned int object_size;/* The size of an object without meta data */
	unsigned int offset;	/* Free pointer offset. */
#ifdef CONFIG_SLUB_CPU_PARTIAL
	/* Number of per cpu partial objects to keep around */
	unsigned int cpu_partial;
#endif
	struct kmem_cache_order_objects oo;

	/* Allocation and freeing of slabs */
	struct kmem_cache_order_objects max;
	struct kmem_cache_order_objects min;
	gfp_t allocflags;	/* gfp flags to use on each alloc */
	int refcount;		/* Refcount for slab cache destroy */
	void (*ctor)(void *);
	unsigned int inuse;		/* Offset to metadata */
	unsigned int align;		/* Alignment */
	unsigned int red_left_pad;	/* Left redzone padding size */
	const char *name;	/* Name (only for display!) */
	struct list_head list;	/* List of slab caches */
#ifdef CONFIG_SYSFS
	struct kobject kobj;	/* For sysfs */
	struct work_struct kobj_remove_work;
#endif
#ifdef CONFIG_MEMCG
	struct memcg_cache_params memcg_params;
	/* for propagation, maximum size of a stored attr */
	unsigned int max_attr_size;
#ifdef CONFIG_SYSFS
	struct kset *memcg_kset;
#endif
#endif

#ifdef CONFIG_SLAB_FREELIST_HARDENED
	unsigned long random;
#endif

#ifdef CONFIG_NUMA
	/*
	 * Defragmentation by allocating from a remote node.
	 */
	unsigned int remote_node_defrag_ratio;
#endif

#ifdef CONFIG_SLAB_FREELIST_RANDOM
	unsigned int *random_seq;
#endif

#ifdef CONFIG_KASAN
	struct kasan_cache kasan_info;
#endif

	unsigned int useroffset;	/* Usercopy region offset */
	unsigned int usersize;		/* Usercopy region size */

	struct kmem_cache_node *node[MAX_NUMNODES];
};

其中cpu_slab是__percpu类型的,这正是前面分析出错的原因所在。

3 percpu变量的实现

        percpu变量是一项内核特性,创建一个percpu变量后每个CPU上都会有一个此变量的副本,CPU在访问其副本时无需加锁,可以放入自己的cache中,极大地提高了访问与更新效率。

3.1 percpu变量的定义

内核提供了DEFINE_PER_CPU宏来定义percpu变量,其定义如下:

#define DEFINE_PER_CPU(type, name)					\
	DEFINE_PER_CPU_SECTION(type, name, "")

 DEFINE_PER_CPU_SECTION、__PCPU_ATTRS和PER_CPU_BASE_SECTION的定义如下:

#define PER_CPU_BASE_SECTION ".data..percpu"

#define __PCPU_ATTRS(sec)						\
	__percpu __attribute__((section(PER_CPU_BASE_SECTION sec)))	\
	PER_CPU_ATTRIBUTES

#define DEFINE_PER_CPU_SECTION(type, name, sec)				\
	__PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES			\
	__typeof__(type) name
#endif

#ifndef PER_CPU_ATTRIBUTES
#define PER_CPU_ATTRIBUTES
#endif

#ifndef PER_CPU_DEF_ATTRIBUTES
#define PER_CPU_DEF_ATTRIBUTES
#endif

 DEFINE_PER_CPU宏展开后就是这样的:

	__percpu __attribute__((section(".data..percpu" sec)))			\
	__typeof__(type) name

举例来说,通过DEFINE_PER_CPU(int, per_cpu_n)定义变量per_cpu_n,展开后是这样的:

	__percpu __attribute__((section(".data..percpu" sec))) int per_cpu_n

这与 struct kmem_cache结构体的cpu_slab成员的定义:

struct kmem_cache_cpu __percpu *cpu_slab;

类似。

percpu变量的实现较为复杂,建议参考这篇文章做详细了解。

3.2 percpu变量的访问

1个percpu变量NR_CPUS+1个实体(比较浪费空间),其中NR_CPUS个是每个CPU的副本,CPU在访问时都直接访问自己的副本。仍然以:

DEFINE_PER_CPU(int, per_cpu_n);

为例,加入NR_CPUS为2,那么定义了一个:

int per_cpu_n; //为方便,我们称其为正本

变量,以及两个CPU副本:

int per_cpu_n; //副本0

int per_cpu_n; //副本1

CPU0和CPU1在访问per_cpu_n时分别访问自己的副本,而正本却没有谁去访问!

现在回到我们前面的问题,我们访问kmalloc_caches[6].cpu_slab时,实际是访问了正本,而非副本,但恰恰正本是没有谁在使用的,所以我们看到其成员值都为0。

现在问题来了,CPU副本是如何访问的呢?其实很简单,linux内核提供了一个__per_cpu_offset[NR_CPUS]数组,数组中保存了percpu变量对应的offset值,访问时通过该offset值+正本地址,得到的就是其副本的地址。比如per_cpu_n 对应CPU0的副本地址是:

__per_cpu_offset[0] + per_cpu_n

回到我们前面的panic问题,查看__per_cpu_offset值:

  __per_cpu_offset = (
    0x0624B000,
    0x0625D000)

CPU 0对应的cpu_slab地址为:

0xC0530BF0 + 0x0624B000 = 0xC678BBF0

 转换成kmem_cache_cpu结构:


(struct kmem_cache_cpu*)0xc677bbf0 = 0xC677BBF0 -> (
    freelist = 0x1,
    tid = 0x0001ED30,
    page = 0xC685E5E0)

CPU 1对应的cpu_slab地址为:

0xC0530BF0 + 0x0625D000 = 0xC678DBF0

转换成kmem_cache_cpu结构:

(struct kmem_cache_cpu*)0xC678DBF0 = 0xC678DBF0 -> (
    freelist = 0xC4421740,
    tid = 29805,
    page = 0xC683F420)

这里CPU 0的 cpu_slab->freelist为1,与panic现场一致。但CPU 1的cpu_slab->freelist为0xC4421740,并不为1。这是为何?

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

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

相关文章

AXI UART 16550 IP核简介

AXI UART 16550 IP核实现了PC16550D UART的硬件和软件功能&#xff0c;该UART可以在16450和16550 UART模式下工作。 一、 功能 AXI UART 16550 IP核执行从AXI主设备接收的字符的并行到串行转换&#xff0c;以及从调制解调器或串行外设接收的字符的串行到并行转换。它支持发送…

GPT3.5、GPT4、GPT4o的性能对比

理论总结 随着版本的升级,模型在参数数量、语言理解能力、生成文本质量、多模态能力、推理能力等方面均有显著提升。GPT-4.0作为最新改进版,提供了最先进的功能和性能。 实际对比 1.1.GPT3.5 1.2.GPT4 1.3.GPT4o 在语义理解上,无差别。 下面测试下代码能力。 测试问题 我…

uni-app:音频播放 uni.createInnerAudioContext()

uni.createInnerAudioContext() 创建并返回内部 audio 上下文 innerAudioContext 对象 简单实现音频播放&#xff1a; let innerAudioContext uni.createInnerAudioContext(); innerAudioContext.src ../../../../static/ok.MP3;//音频地址 innerAudioContext.play(); inn…

Pikachu 靶场 SQL 注入通关解析

前言 Pikachu靶场是一种常见的网络安全训练平台&#xff0c;用于模拟真实世界中的网络攻击和防御场景。它提供了一系列的实验室环境&#xff0c;供安全专业人士、学生和爱好者练习和测试他们的技能。 Pikachu靶场的目的是帮助用户了解和掌握网络攻击的原理和技术&#xff0c;…

【案例】使用Vue实现拖拽课表

效果展示 效果说明 点击左侧的课程并进行拖拽&#xff0c;拖拽到要开设本课程的地方然后松手&#xff0c;即可将本节课设置为当前所拖拽的科目并且背景色为当前科目的背景色&#xff0c;当多次拖拽到同一节课的时候将会实现后者覆盖前者的效果。 效果实现代码 第一步&#x…

波场TRON超级代表候选名单“迎新” 携手谷歌云打造更可靠基础设施

来自波场TRON DAO的信息显示,谷歌云已加入波场TRON区块链上的超级代表候选名单。分析人士认为,这将为波场TRON网络提供更加稳定和可靠的区块生成和交易打包服务,有助于进一步加强波场TRON网络的安全性和稳定性,推动区块链技术的发展和创新。此举也将提高波场TRON在加密货币领域…

一图流解释Java中线程状态的转换

目录 一.Java中的几大线程状态 二.线程之间的相互转换 ▐ NEW --> RUNNABLE ▐ RUNNABLE <--> WAITING ▐ RUNNABLE <--> Timed Waiting ▐ RUNNABLE<--> BLOCKED ▐ RUNNABLE<-->TERMINATED 一.Java中的几大线程状态 简单来说线程可以处于…

VC++6.0 Sqlite3调用例子

1,为什么要使用Sqlite3? SQLite 是一个软件库&#xff0c;实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。 2,为什么使用SQLite version 3.8.4.3 2014-04-03 16:53:12的版本…

新书速览|Django 5 Web应用开发实战

构建未来&#xff0c;用Django 5打造全新Web应用 本书内容 《Django 5 Web应用开发实战》集Django架站基础、项目实践、开发经验于一体&#xff0c;是一本从零基础到精通Django Web企业级开发技术的实战指南。《Django 5 Web应用开发实战》内容以Python 3.x和Django 5版本为基础…

为什么需要使用SOCKS5代理?

SOCKS代表Socket Secure&#xff0c;是一种网络协议&#xff0c;能够在网络上进行数据传输。SOCKS5是SOCKS协议的第五个版本&#xff0c;它提供了更加安全和灵活的数据传输方式&#xff0c;因此在网络安全和隐私保护方面被广泛应用。在我们的日常生活中&#xff0c;为什么需要使…

new delete用法它们与 malloc free 的区别

文章目录 new 和 delete的用法operate new() operate delete() new delete 和 malloc free的区别new[] delete[] 的含义 new 和 delete的用法 基本写法&#xff0c;new也是先申请空间 这里的new和malloc用的地方一样但是new用起来代码简洁不少而且不需要强转和指定大小 int m…

移动烽火HG光猫超密破解

1、查找mac地址 cmd 运行 arp -a 192.168.1.1 2、开启telnet功能 浏览器输入 http://192.168.1.1/cgi-bin/telnetenable.cgi?telnetenable1&key3086F178B450 注释&#xff1a; telnetenable1 开启telnet功能 key 是第一步查询的mac地址&#xff0c;去掉横线、小写…

四.Ubuntu安装postgresql数据库

四&#xff0e;Ubuntu安装postgresql数据库 1.安装postgresql数据库命令&#xff1a;apt install postgresql postgresql-contrib 依次回车,等待安装完成。 2.以postgres用户登录PostgreSQL&#xff0c;命令&#xff1a;sudo -u postgres psql 修改postgres密码命令&#x…

MySQL数据库基础--性能分析,使用规则

SQL性能分析 SQL执行频率 MySQL客户端连接成功后&#xff0c;通过 show [session|global] 命令可以提供服务器状态信息。通过如下指令&#xff0c;可以查看当前数据库的INSERT,UPDATE,DELETE,SELECT的访问频次。 慢查询日志 慢查询日志记录了所有执行时间超过指定参数&#…

vue3使用el-radio-group获取表格数据无法选中问题

这里是引用 今天写项目发现使用el-radio-group无法获取表格中的数据&#xff0c;于是去官网查看了一下&#xff0c;发现写的没啥问题&#xff0c;就是 <el-radio value"1" size"large"> 未知</el-radio>这样的写法&#xff0c;又在网上看了一些…

蓝桥杯练习系统(算法训练)ALGO-941 P0601字符删除

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 编写一个程序&#xff0c;先输入一个字符串str&#xff08;长度不超过20&#xff09;&#xff0c;再输入单独的一个字符ch&#xff0c…

LVS负载均衡超详细入门介绍

LVS 一、LVS入门介绍 1.1.LVS负载均衡简介 1.2.负载均衡的工作模式 1.2.1.地址转换NAT&#xff08;Network Address Translation&#xff09; 1.2.2.IP隧道TUN&#xff08;IP Tunneling&#xff09; 1.2.3.直接路由DR&#xff08;Direct Routing&#xff09; 1.3.…

JavaScript中带日期的操作

当我们把日期转换为Number类型的时候&#xff0c;就会变成时间戳&#xff08;毫秒&#xff09; const future new Date(2037, 10, 19, 15, 23); console.log(Number(future)); // console.log(future); //与上行代码等效● 所以我们就可以利用时间戳去做点东西&#xff0c;例…

Oceanbase 4.3特性解析:用物化视图来优化复杂查询

如果你是一位数据分析师&#xff0c;需要在包含数百万行数据的数据库中频繁地检索特定信息&#xff0c;而每次这样的查询都伴随着复杂的计算&#xff0c;耗费大量时间和资源。你可以考虑采用物化视图这一功能&#xff0c;提高查询效率。 物化视图是什么&#xff1f; 物化视图…

机器视觉中的打光技巧、选择光源的流程

目录 基本原则选择照明的考虑因素明场照明和暗场照明全明场照明&#xff08;漫射照明&#xff09;技术 特定光源1. 环形光源2. 条形光源3. 同轴光源3.1 何时使用同轴照明&#xff1f;3.2 何时不使用同轴照明&#xff1f; 4. 背光源5. 远心照明6. 点光源7. 穹顶光源8. 线光源9. …