Android HWASAN使用与实现原理

一、背景

为了提前检测出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:           00Partially addressable: 01 02 03 04 05 06 07 Heap left redzone:     fa (实际上Heap right redzone也是fa)Freed Heap region:     fdStack left redzone:    f1Stack mid redzone:     f2Stack right redzone:   f3Stack after return:    f5Stack use after scope: f8Global redzone:        f9Global init order:     f6Poisoned by user:      f7Container overflow:    fcArray cookie:          acIntra object redzone:  bbASan internal:         feLeft alloca redzone:   caRight alloca redzone:  cbShadow 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: 0Cause: 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.mzph.cn/web/40423.shtml

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

相关文章

ES8.13.0 java client请求响应报错status: 200, [es/search] Failed to decode response

最近在做商城项目使用ES8.13.0做商品复杂的检索功能时&#xff0c;遇到一个报错如下&#xff1a; 2024-07-05 10:47:53.994 ERROR 10708 --- [nio-7500-exec-1] com.tfq.exception.RRExceptionHandler : co.elastic.clients.transport.TransportException: node: http://1…

WBCE CMS v1.5.2 远程命令执行漏洞(CVE-2022-25099)

前言 CVE-2022-25099 是一个影响 WBCE CMS v1.5.2 的严重安全漏洞&#xff0c;具体存在于 /languages/index.php 组件中。该漏洞允许攻击者通过上传精心构造的 PHP 文件在受影响的系统上执行任意代码。 技术细节 受影响组件&#xff1a;/languages/index.php受影响版本&…

如何在 Odoo 16 中向新视图添加字段

例如,让我们看看如何在新视图或新操作窗口中创建“many2one”字段。 请考虑下面的屏幕截图,它表示不包含任何字段的新视图类型或客户端操作窗口。 我们现在可以将与“res.partner”关联的“多对一”字段引入到我们的新视图或客户端操作窗口中。 为了实现这一点,在 XML 模板…

ShardingSphere

ShardingSphere 是一个开源的分布式数据库中间件生态系统&#xff0c;由 Apache 基金会孵化和维护。它的主要目标是帮助开发者解决分库分表、分布式事务和数据加密等分布式数据库应用中的常见问题。ShardingSphere 提供了多种组件&#xff0c;如 Sharding-JDBC、Sharding-Proxy…

Using a text embedding model locally with semantic kernel

题意&#xff1a;在本地使用带有语义核&#xff08;Semantic Kernel&#xff09;的文本嵌入模型 问题背景&#xff1a; Ive been reading Stephen Toubs blog post about building a simple console-based .NET chat application from the ground up with semantic-kernel. Im…

idea中maven全局配置

配置了就不需要每次创建项目都来设置maven仓库了。 1.先把项目全关了 2. 进入全局设置 3.设置maven的仓库就可以了

SpringBoot实现多数据源切换

1. 概述 随着项目规模的扩大和业务需求的复杂化&#xff0c;单一数据源已经不能满足实际开发中的需求。在许多情况下&#xff0c;我们需要同时操作多个数据库&#xff0c;或者需要将不同类型的数据存储在不同的数据库中。这时&#xff0c;多数据源场景成为必不可少的解决方案。…

【CentOS7.6】docker部署EMQX教程,本地镜像直接导入(附下载链接),没法在云服务器上魔法拉取镜像的快来

总览 先把下载链接放在这里吧&#xff0c;这是 EMQX 的 tar 包&#xff0c;能够直接导入 CentOS 的 docker&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rSGSLoVvj83ai6d5oolg8Q?pwd0108 提取码&#xff1a;0108 一、安装配置教程 1.将 EMQX-latest.tar 包导入…

服务器重装系统时数据丢失?有哪些方法可以避免

为了避免在服务器重装系统时数据丢失&#xff0c;可以采取以下预防措施&#xff1a; 1. 数据备份&#xff1a;在重装系统之前&#xff0c;备份所有重要的数据和配置文件。备份可以通过以下方式进行&#xff1a; - 使用外部存储设备(如USB硬盘、NAS等)进行备份。 - 利用备份软件…

学习成绩总是上不去?中学生把握好这5个环节,助你提高成绩

在中学时代&#xff0c;考试我们并不陌生。每隔一段时间&#xff0c;学校就会安排我们参加考试。学生时代&#xff0c;我们参加的考试有很多。对于中学生来说&#xff0c;考试成绩是我们一直关心的事情。很多学生非常努力的学习&#xff0c;成绩却上不去。这是非常可惜的&#…

[图解]企业应用架构模式2024新译本讲解19-数据映射器1

1 00:00:01,720 --> 00:00:03,950 下一个我们要讲的就是 2 00:00:04,660 --> 00:00:07,420 数据映射器这个模式 3 00:00:09,760 --> 00:00:13,420 这个也是在数据源模式里面 4 00:00:13,430 --> 00:00:14,820 用得最广泛的 5 00:00:16,250 --> 00:00:19,170…

【软件工程中的喷泉模型及其优缺点】

文章目录 一、喷泉模型是什么&#xff1f;二、喷泉模型的优点1. 灵活性和适应性2. 迭代开发3. 风险控制 三、喷泉模型的缺点1. 需求不明确性2. 可能造成资源浪费3. 需要良好的沟通与协作 一、喷泉模型是什么&#xff1f; 喷泉模型是一种迭代增量开发模型&#xff0c;其核心理念…

链篦机回转窑球团生产工艺

生球在回转窑氧化焙烧&#xff0c;回转窑头部设有燃烧器&#xff0c;燃料可以采用气体、固体、液体。 来自环冷机一冷却段的高温废气作为二次风进入窑内参与燃烧&#xff0c;烧成成品球进入环冷机。 环冷机采用鼓风冷却&#xff0c;热风风箱分为四段&#xff1a; 一段气体引至…

无人机有哪些关键技术?

一、控制技术 无人机的核心还是在控制上&#xff0c;飞控系统的可靠性、稳定性及可扩展性是其中重要的指标。可靠性上&#xff0c;除了器件选型之外&#xff0c;目前主要靠多余度来增加&#xff1b;稳定性主要体现在多场景下仍能保持良好的工作状态&#xff0c;主要靠算法来进…

QML-各类布局

Colunm布局 Column{id:colspacing: 30Repeater{id:repmodel: ListModel{}Button{width: 100height: 50text: "btn"index}}//开始时候移动move: Transition {NumberAnimation { properties: "x,y"; easing.type: Easing.OutBounce }}//添加时变化add:Transi…

【Nginx】docker运行Nginx及配置

Nginx镜像的获取 直接从Docker Hub拉取Nginx镜像通过Dockerfile构建Nginx镜像后拉取 二者区别 主要区别在于定制化程度和构建过程的控制&#xff1a; 直接拉取Nginx镜像&#xff1a; 简便性&#xff1a;直接使用docker pull nginx命令可以快速拉取官方的Nginx镜像。这个过程…

通透!手把教你如何从头构建一个机器学习模型

目录 1.业务理解 2.数据收集和准备 数据采集 探索性数据分析 (EDA) 和数据清理 特征选择 3.建立机器学习模型 选择正确的模型 分割数据 训练模型 模型评估 4.模型优化 5.部署模型 今天我将带领大家一步步的来构建一个机器学习模型。 我们将按照以下步骤开发客户流失…

赛博解压板

目录 开头程序程序的流程图程序的解压效果(暂无&#xff0c;但可以运行一下上面的代码)结尾 开头 大家好&#xff0c;我叫这是我58。今天&#xff0c;我们要看关于赛博解压板的一些东西。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #define ROW 6//ROW表示行数&#xff0c;可…

【ARM 常见汇编指令学习 7.1 -- LDRH 半字读取指令】

请阅读【嵌入式开发学习必备专栏】 文章目录 LDRH 使用介绍LDRH&#xff08;Load Register Half-word&#xff09;总结 LDRH 使用介绍 在ARMv9架构中&#xff0c;汇编指令LDRH用于从内存中载入数据到寄存器的指令&#xff0c;下面将分别对它进行详细介绍&#xff1a; LDRH&am…

【基础算法】UE中实现轮播

本期作者&#xff1a;尼克 易知微3D引擎技术负责人 当前N 总数M 从0到M-1 从1到M 感谢阅读&#xff0c;以上内容均由易知微3D引擎团队原创设计&#xff0c;以及易知微版权所有&#xff0c;转载请注明出处&#xff0c;违者必究&#xff0c;谢谢您的合作。申请转载授权后台回复【…