Android HWASAN使用与实现原理

news2024/10/6 20:37:38

一、背景

为了提前检测出Android User Sapce的app或native进程的内存错误问题,帮助研发定位与分析这些问题,基于Android 14版本上对HWASAN做了调研分析。

二、ASAN介绍

HWASAN是在ASAN的基础上做了拓展,因此在介绍HWASAN之前先了解下ASAN.

ASAN(AddressSanitizer)和HWASAN(Hardware-assisted AddressSanitizer)都是内存错误检测工具,用于帮助开发者发现和修复内存相关的bug,如heap-buffer-overflow、Heap-use-after-free、stack-buffer-overflow、global-buffer-overflow、double-free、Use-after-return、Alloc-dealloc-mismatch、use-after-poision等内存错误问题。它们的主要区别在于实现方式和性能开销。

2.1 shadow memory

shadow memory区域来记录实际内存的状态信息,malloc申请的内存或其它方式申请的内存一般8字节对齐,8字节的正常内存对应1个字节的shadow memory,8个字节中可划分为可寻址(访问)与不可寻址区域。如,前4个字节可寻址,后4个字节不可寻址,shadow memory记录的数据为5,即0000 0100.

normal mem与shadow mem对应关系:

shadow memory address = (normal memory address >> 3) + 0x1000000000

8字节组成的normal memory region共有3种状态:

1)1~7个字节可寻址,即shadow memory的值为1~7。

2)8个字节都可寻址,即shadow memory的值为0。

3)0个字节可寻址,shadow memory的值为负数。

0个字节可寻址其实可以分为多种情况,如:

这块区域是heap redzones、stack redzones、global redzones、freed memory,不同错误类型对应的shadow memory值也不一样。

 Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:     fa (实际上Heap right redzone也是fa)
  Freed Heap region:     fd
  Stack left redzone:    f1
  Stack mid redzone:     f2
  Stack right redzone:   f3
  Stack after return:    f5
  Stack use after scope: f8
  Global redzone:        f9
  Global init order:     f6
  Poisoned by user:      f7
  Container overflow:    fc
  Array cookie:          ac
  Intra object redzone:  bb
  ASan internal:         fe
  Left alloca redzone:   ca
  Right alloca redzone:  cb
  Shadow gap:            cc

每次访问normal memory地址时,都会去结合对应的shadow mem的值检测是否合法。

2.2 ASAN实现原理

ASAN实现原理:通过在内存分配时插入额外的代码来检查内存访问是否合法。使用一个影子内存(shadow memory)区域来记录实际内存的使用情况,当检测到非法内存访问时,ASAN会报告错误。

检测算法:

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k))
        ReportAndCrash(Addr);

k!=0,说明Normal memory region中的8个字节并不是都可以被寻址的。

Addr & 7,将得知此次内存访问是从memory region的第几个byte开始的。

AccessSize是此次内存访问需要访问的字节长度。

(Addr&7)+AccessSize > k,则说明此次内存访问将会访问到不可寻址的字节。

当此次内存访问可能会访问到不可寻址的字节时,ASAN会报错并结合shadow memory中具体的值明确错误类型。

下面以use-after-free、heap-buffer-overflow来分析具体的检测原理。

2.2.1 use-after-free检测

检测原理:

1)已经free的normal memory对应的shadow memory值为0xfd.

2)已经free的normal memory区域需要放入隔离区一段时间(过段时间才允许被重新分配),防止发生错误时该区域已经通过malloc重新分配给其他人使用。一旦分配给其他人使用,则可能漏掉UseAfterFree的错误。

3)如果再次访问该normal memory区域时,发现对应的shadow memory值为0xfd,则触发ASAN异常报错。

2.2.2 heap-buffer-overflow检测

检测原理:

1)分配内存时normal memory的前后需要插入一定长度的安全区(大小不定),且此安全区对应的shadow memory被标记为0xfa.

2)当访问越界时,刚好访问了normal memory的前后安全区,此安全区对应的shadow memory值为0xfa,则触发ASAN异常报错。

2.3 ASAN缺陷

2.3.1 存在漏检的风险

1)use-after-free检测依赖隔离区,一段时间后这块内存被其他模块重新分配后,该模块再去访问,则无法检测出use-after-ree的错误。


2)heap-buffer-overflow检测依赖安全区,安全区有大小限制。可能是8bytes,64bytes或者其他什么值,但不管怎么样终归是有限的。如果某次踩踏跨过了安全区,踩踏到另一片可寻址的内存区域,则无法检测出heap-buffer-overflow的错误。

2.3.2 性能开销大

有两个原因导致ASAN性能开销:

1)增加额外的内存消耗:8字节的normal memory对应1个字节的shadow memory,相当于额外多出1/8的内存用于记录正常内存的状态信息;内存分配时需要在前后插入安全区,用于检测越界访问。这两种情况都会导致内存增加。

2)效率降低:需要在每次内存访问时进行检查,降低了效率;被释放的内存,需被隔离一段时间,无法立即被重新分配,系统内存紧张时,可能存在较大的性能影响

因此,针对ASAN的存在漏检的风险和性能开销大的缺陷,google提出了HWASAN来改善这两大缺陷。HWASAN解决措施:

1)措施1:64位的机器,实际上ARMv8寻址只用到了低48位,因此malloc时,HWASAN利用高8位标记tag,对应的shadow memory的值也记做tag

由于HWASAN 16字节的normal memory对应1个字节的shadow memory(ASAN为8:1),降低额外内存的消耗;由于HWASAN use-after-free检测不依赖隔离区,解决use-after-free漏检的风险(详细参考3.1.1)。

2)措施2:去除ASAN安全区的内存机制

由于去除ASAN安全区的内存机制,被释放的内存可以被其他模块立即分配,从而提高了内存的利用效率;

同时可以解决heap-buffer-overflow漏检的风险(详细参考3.1.2)。

三、HWASAN介绍

HWASAN是ASAN的升级版,优化了ASAN性能开销和漏检风险的缺陷。

3.1 实现原理

实现原理:64位的机器,实际上ARMv8寻址只用到了低48位。HWASAN用这8bit来存储一块内存区域的标签(tag)。

堆内存通过malloc分配出来,HWASAN在它返回地址时会更改该有效地址的高8位,随机生成一个tag数值,并将该tag同步到内存对应的shadow memory,当内存释放时,更新shadow memory的tag,HWASAN中normal memory和shadow memory的映射关系是16:1,而ASAN中二者的映射关系是8:1。通过对比内存高8位的tag与shadow memory的tag是否一致,如果不一致,会触发HWASAN相关的内存错误。

下面以use-after-free、heap-buffer-overflow来分析具体的检测原理。

3.1.1 use-after-free检测

检测原理:

1)分配一块内存时,内存的高8位打上tag,对应的shadow memory的值也为该tag

2)内存释放时,更新对应的shadow memory的tag,使这块内存的高8位的tag与shadow memory的tag不一致

3)当再次访问这块内存时,发现内存的高8位的tag与shadow memory的tag不一致,触发HWASAN内存错误

如,char* p =new char[10],分配10个字节的内存,由于8个字节对齐,共占用16个字节,高8位随机生成tag1。

当内存释放时,对应的shadow memory的值由原来的tag1更新位tag2.再次访问p[0]时,检查高8位tag1与shadow memory中的值tag2不一致,触发HWASAN use-after-free.

char* p =new char[10];
delete [] p;
p[0] = "abc";

3.1.2 heap-buffer-overflow检测

检测原理:

1)相邻内存的shadow memory的tag不一致

2)当访问这块内存地址时,会去检测该地址高8位的tag与对应shadow memory的tag是否一直不一致。如果不一致,说明越界访问

如,char* p =new char[10],分配10个字节的内存,由于8个字节对齐,共占用16个字节,高8位随机生成tag2。当访问p[16]时,由于p+16所处地址对应的shadow memory的值为tag3与p地址对应的高8位tag2不一致,会触发HWASAN heap-buffer-overflow.

char* p =new char[10];
p[16] = "abc";

由于每次malloc,高8位的tag随机生成,因此存在相邻内存高8位的tag一致的概率(如tag2等于tag3),概率为1/256,在这种情况下即使越界访问,也无法检测出heap-buffer-overflow的问题。

3.2 HWASAN优缺点

优点:

解决了ASAN的缺陷

缺点:

1)由于采用了高8位的tag检测机制,因此只能适用于64位的机器

2)HWASAN中normal memory和shadow memory的映射关系是16:1,即会多消耗1/16的额外内存用于记录normal memory的状态(tag)信息

3)每次内存分配、释放、访问,都需要额外的检测工作,降低性能

4.1 系统全功能打开

1)编译带HWASAN的镜像和带hwasan的libc.so & libclang_rt.hwasan-aarch64-android.so

source build/envsetup.sh
lunch missi_auto_native_only64-userdebug
export SANITIZE_TARGET=hwaddress
make -j8 或make systemimage

libc.so路径:

out/target/product/missi/system/lib64/bootstrap/hwasan/libc.so

libclang_rt.hwasan-aarch64-android.so路径:out/target/product/missi/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so

2)刷机或push libc.so和libclang_rt.hwasan-aarch64-android.so到/system/lib64目录后重启设备

4.2 单个应用或进程打开

AndroidManifest.xml中 <application> 元素中配置了 android:debuggable="true"

<application android:debuggable="true">

</application>

native进程开启HWASAN,需要在Android.bp中做配置:

sanitize: {
    hwaddress: true,
},

五、Debug案例

在设备验证HWASAN功能:

1)设置HWASAN环境变量,编译出带HWASAN的镜像或libc.so + libclang_rt.hwasan-aarch64-android.so

source build/envsetup.sh
lunch missi_auto_native_only64-userdebug
export SANITIZE_TARGET=hwaddress
make -j8 或make systemimage

带hwasan的libc.so路径:

out/target/product/missi/system/lib64/bootstrap/hwasan/libc.so

libclang_rt.hwasan-aarch64-android.so路径:out/target/product/missi/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so

(刷机方式效率较低,可以直接push so库到设备)

2)push libc.so和libclang_rt.hwasan-aarch64-android.so到/system/lib64目录后重启设备

3)自己编写一个Demo,push hw-asan-test-bin Demo到/system/bin目录并执行

检测double-free、use-after-free、invalid-free、heap-over-flow等场景,

分别执行./system/bin/hw-asan-test-bin double-free、./system/bin/hw-asan-test-bin use-after-free、./system/bin/hw-asan-test-bin heap-over-flow命令。

Demo的部分代码:

void doubleFree() {
    // 分配4个字节
    int *ptr = (int*)malloc(4);
    std::cout << "ptr = " << ptr << std::endl;
    free(ptr);
    free(ptr);
}

void invalidFree() {
    int *ptr = (int*)malloc(4);
    std::cout << "ptr = " << ptr << std::endl;
    free(ptr+1);
    std::cout << "invalid-free ~" << std::endl;
}

void useAfterFree() {
    char* ptr = new char[20];
    std::cout << "ptr = " << ptr << std::endl;
    delete[] ptr;
    ptr[0] = 'A';
    std::cout << "useAfterFree ~" << std::endl;
}

void heapOverFlow() {
    char* ptr = new char[20];
    std::cout << "ptr = " << ptr << std::endl;
    ptr[32] = 'A';
    std::cout << "heapOverFlow ~" << std::endl;
}

void memLeak() {
    for (int i = 0; i < 1000; i++) {
        char *buffer = (char *)malloc(100);
    }
    std::cout << "memLeak ~" << std::endl;
}

4)查询生成的tombstone文件

以下是hw-asan-test-bin Demo crash生成的HWASAN tombstone文件,如下:

Cmdline: ./system/bin/hw-asan-test-bin double-free
pid: 12968, tid: 12968, name: hw-asan-test-bi  >>> ./system/bin/hw-asan-test-bin <<<
uid: 0
tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
// 内存被释放后,0x003c95840020地址对应的内存被标记为6c
Abort message: '==12968==ERROR: HWAddressSanitizer: invalid-free on address 0x003c95840020 at pc 0x007d0dd81ba4 on thread T0
tags: 77/6c (ptr/mem)
    #0 0x7d0dd81ba4  (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x23ba4) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
    #1 0x5b9584c230  (/system/bin/hw-asan-test-bin+0x1230) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
    #2 0x5b9584c6a4  (/system/bin/hw-asan-test-bin+0x16a4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
    #3 0x7d0aab6b60  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0xb0b60) (BuildId: 86a860a589207e712675d7d611b13147)
    #4 0x5b9584c054  (/system/bin/hw-asan-test-bin+0x1054) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)

[0x003c95840020,0x003c95840040) is a small unallocated heap chunk; size: 32 offset: 0

Cause: use-after-free
// 分配的内存地址0x003c95840020至0x003c95840024,刚好是4个字节与Demo代码一致
0x003c95840020 is located 0 bytes inside a 4-byte region [0x003c95840020,0x003c95840024)
// HWASAN内存释放的堆栈信息
freed by thread T0 here:
    #0 0x7d0dd81ba4  (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x23ba4) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
    #1 0x5b9584c188  (/system/bin/hw-asan-test-bin+0x1188) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
    #2 0x5b9584c6a4  (/system/bin/hw-asan-test-bin+0x16a4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
    #3 0x7d0aab6b60  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0xb0b60) (BuildId: 86a860a589207e712675d7d611b13147)
    #4 0x5b9584c054  (/system/bin/hw-asan-test-bin+0x1054) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
// HWASAN内存分配的堆栈信息
previously allocated here:
    #0 0x7d0dd82244  (/system/lib64/libclang_rt.hwasan-aarch64-android.so+0x24244) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
    #1 0x7d0aa671dc  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0x611dc) (BuildId: 86a860a589207e712675d7d611b13147)
    #2 0x5b9584c0d4  (/system/bin/hw-asan-test-bin+0x10d4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
    #3 0x5b9584c6a4  (/system/bin/hw-asan-test-bin+0x16a4) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
    #4 0x7d0aab6b60  (/apex/com.android.runtime/lib64/bionic/hwasan/libc.so+0xb0b60) (BuildId: 86a860a589207e712675d7d611b13147)
    #5 0x5b9584c054  (/system/bin/hw-asan-test-bin+0x1054) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)

hwasan_dev_note_heap_rb_distance: 1 1023
hwasan_dev_note_num_matching_addrs: 0
hwasan_dev_note_num_matching_addrs_4b: 0
Thread: T0 0x007400002000 stack: [0x007fc95fb000,0x007fc9dfb000) sz: 8388608 tls: [0x007d0ea6efc0,0x007d0ea72000)
Memory tags around the buggy address (one tag corresponds to 16 bytes):
  0x003c9583f800: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c9583f900: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c9583fa00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c9583fb00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c9583fc00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c9583fd00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c9583fe00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c9583ff00: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
=>0x003c95840000: 08  00 [6c] 00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840100: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840200: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840300: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840400: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840500: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840600: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840700: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
  0x003c95840800: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00 
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
  0x003c9583ff00: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. 
=>0x003c95840000: 6e  .. [..] ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. 
  0x003c95840100: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  .. 
  
  ......
  backtrace:
      #00 pc 00000000000bab8c  /apex/com.android.runtime/lib64/bionic/hwasan/libc.so (abort+308) (BuildId: 86a860a589207e712675d7d611b13147)
      #01 pc 00000000000354b4  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__sanitizer::Abort()+60) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
      #02 pc 0000000000033d3c  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__sanitizer::Die()+204) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
      #03 pc 00000000000286c4  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__hwasan::ScopedReport::~ScopedReport()+544) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
      #04 pc 0000000000027458  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__hwasan::ReportInvalidFree(__sanitizer::StackTrace*, unsigned long)+560) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
      #05 pc 0000000000023c00  /system/lib64/libclang_rt.hwasan-aarch64-android.so (__sanitizer_free+264) (BuildId: 558b5c131872716737ddc0a62f3382dd3df70b9a)
      #06 pc 0000000000001230  /system/bin/hw-asan-test-bin (doubleFree()+472) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
      #07 pc 00000000000016a4  /system/bin/hw-asan-test-bin (main+648) (BuildId: b3d99e0748a4c4a2607c8c2b9b91815e)
      #08 pc 00000000000b0b60  /apex/com.android.runtime/lib64/bionic/hwasan/libc.so (__libc_init+148) (BuildId: 86a860a589207e712675d7d611b13147)
      ......

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

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

相关文章

C#的五大设计原则-solid原则

什么是C#的五大设计原则&#xff0c;我们用人话来解释一下&#xff0c;希望小伙伴们能学会&#xff1a; 好的&#xff0c;让我们以一种幽默的方式来解释C#的五大设计原则&#xff08;SOLID&#xff09;&#xff1a; 单一职责原则&#xff08;Single Responsibility Principle…

更好的方法_交叉观察器API

交叉观察器&#xff08;Intersection Observer&#xff09;API 是一个强大的工具&#xff0c;可以用来检测元素是否进入视口或从视口移出。我们可以利用这个 API 来实现粘贴式导航&#xff08;也称为粘性导航&#xff09;&#xff0c;即在用户滚动页面时&#xff0c;导航栏会在…

简单分享 for循环,从基础到高级

1. 基础篇&#xff1a;Hello, For Loop! 想象一下&#xff0c;你想给班上的每位同学发送“Hello!”&#xff0c;怎么办&#xff1f;那就是for循环啦&#xff0c; eg&#xff1a;首先有个名字的列表&#xff0c;for循环取出&#xff0c;分别打印 names ["Alice", …

从零开始实现大语言模型(一):概述

1. 前言 大家好&#xff0c;我是何睿智。我现在在做大语言模型相关工作&#xff0c;我用业余时间写一个专栏&#xff0c;给大家讲讲如何从零开始实现大语言模型。 从零开始实现大语言模型是了解其原理及领域大语言模型实现路径的最好方法&#xff0c;没有之一。已有研究证明&…

服务器BMC基础知识总结

前言 因为对硬件方面不太理解&#xff0c;所以打算先从服务器开始学习&#xff0c;也想和大家一起分享一下&#xff0c;有什么不对的地方可以纠正一下哦&#xff01;谢谢啦&#xff01;互相学习共同成长~ 1.BMC是什么&#xff1f; 官方解释&#xff1a;BMC全名Baseboard Mana…

java面试课程-SpringIOC部分源码解析

1.SpringIOC的refresh源码解析 核心&#xff1a; 核心使用的是&#xff1a; 需要完成配置类的解析&#xff0c;各种BeanFactoryProcessor的注册。还有写国际化配置的初始化。Web容器的内部构造。 上面几个方法是refresh方法的内容。注意可以与applicationContext里的内容一起…

【Linux从入门到放弃】探究进程如何退出以进程等待的前因后果

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《Linux从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 进…

编写动态库

1.创建库.c .h文件 2.编写Makefile文件 3.make之后形成.so文件 4.make output,形成mylib 5.把mylib拷贝到test里面 mv mylib /test 6.编译 gcc main.c -I mylib/include -L mylib/lib -lmymethod形成a.out 但是直接执行会出现以下问题 很显然没有找到动态库 7.解决加载找不…

FIO压测磁盘性能以及需要注意的问题

一、压测类型 1、顺序读&#xff08;IO&#xff09;&#xff1a;read&#xff0c;bs1M&#xff0c;job数从1开始往上加&#xff1a;2、3、4... 2、顺序写&#xff08;IO&#xff09;&#xff1a;write&#xff0c;bs1M&#xff0c;job数从1开始往上加&#xff1a;2、3、4... …

基于索尼基于索尼Spresense的眼睛跟随平台中两个模型的对比

1.模型一(现在使用的) 这个模型是一个简单的神经网络&#xff0c;由三个主要组件组成&#xff1a;输入层、一个全连接层&#xff08;Affine层&#xff09;、一个Sigmoid激活函数层和一个Binary Cross Entropy损失层。 以下是每个组件的说明&#xff1a; Input 层&#xff1a;这…

2024 COMMUNITY DAY User Group 社区嘉年华 云计算与 AI 技术交融盛会共筑多元智慧未来

亚马逊云科技User Group&#xff0c;深圳 Community Day 活动流程抢先知道&#xff01; ⏰ 7月7日 &#x1f3e0; 深圳南山区香港中文大学 &#x1f4e3;主论坛国际大咖云集&#xff0c;共襄科技盛宴&#xff01; &#x1f389;三大主题论坛&#xff1a;人工智能、大数据、动…

heic格式转化jpg,手把手教你将heic转换成jpg【办公必备】

一、什么是heic heic格式是一种高效的图片格式&#xff0c;它可以在较小的文件大小下提供高质量的图片。 二、如何打开heic 然而&#xff0c;这种图片因其格式的特殊性&#xff0c;在实际应用中仍存在一些问题&#xff1a;压缩效果可能不够理想&#xff0c;一些老旧的软件和设…

无线领夹麦克风品牌排名更新,手机直播麦克风前十排名!

在自媒体时代&#xff0c;音频设备尤其是麦克风的重要性日益凸显。技术的革新带来了麦克风品类的多样化&#xff0c;满足了从传统录制到现代自媒体创作的广泛需求。音频质量是决定视频作品能否吸引并留住观众的关键因素。在众多麦克风品牌中&#xff0c;挑选一款性能卓越的产品…

一切为了安全丨2024中国应急(消防)品牌巡展武汉站成功召开!

消防品牌巡展武汉站 6月28日&#xff0c;由中国安全产业协会指导&#xff0c;中国安全产业协会应急创新分会、应急救援产业网联合主办&#xff0c;湖北消防协会协办的“一切为了安全”2024年中国应急(消防)品牌巡展-武汉站成功举办。该巡展旨在展示中国应急&#xff08;消防&am…

【软件测试】单元测试、系统测试、集成测试详解

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、单元测试的概念 单元测试是对软件基本组成单元进行的测试&#xff0c;如函数或一个类的方法…

cesium 聚合

cesium 聚合(下面附有源码) 示例代码 <html lang="en"><head><!-- Use correct character set. -->

AI工具哪里找?这个ai导航网站绝对是你不可错过的宝藏

这两年来&#xff0c;人工智能技术飞速发展并且已经渗透到我们生活的方方面面&#xff0c;从简单的日常任务到复杂的专业领域&#xff0c;AI工具的应用越来越广泛。 无论是办公一族还是设计师&#xff0c;教师等&#xff0c;都开始利用AI&#xff0c;提高自己的工作效率。 如…

QChartView显示实时更新的温度曲线图(动态曲线图)

文章目录 参考图1. 项目结构2. CMakeLists.txt3. main.cpp4. TemperatureSeries.qml5. main.qml6. 说明参考博客参考图 要在Qt QML中使用QChartView显示实时更新的温度曲线图,我们需要使用Qt Charts模块和一些QML组件。下面是一个完整的示例代码,以及详细说明每个部分的作用。…

代码生成器使用指南,JeecgBoot低代码平台

JeecgBoot 提供强大的代码生成器&#xff0c;让前后端代码一键生成&#xff0c;实现低代码开发。支持单表、树列表、一对多、一对一等数据模型&#xff0c;增删改查功能一键生成&#xff0c;菜单配置直接使用。 同时提供强大模板机制&#xff0c;支持自定义模板&#xff0c;目…

基于Canvas的Html5多时区动态时钟实战

目录 前言 一、关于Canvas技术 1、Canvas是什么 2、Canvas的属性及渲染特性 二、Canvas动态多时区展示 1、新建html页面 2、创建Canvas对象 3、绘制所有的时钟 总结 前言 出差旅行相信大家一定会住酒店&#xff0c;大家在酒店的前台进行预订的时候&#xff0c;是不是都…