一.TypedArray类型

TypedArray是漏洞中常见到的结构,手册用法有四

1.new TypedArray(length);
//byteLength=length * sizeof(TypeName);

length
当传入length参数时,一个内部数组缓冲区被创建,该缓存区的大小是传入的length乘以数组中每个元素的字节数,每个元素的值都为0.(译者注:每个元素的字节数是由具体的构造函数决定的,比如Int16Array的每个元素的字节数为2,Int32Array的每个元素的字节数为4)

2.new TypedArray(typedArray); 

typedArray
当传入一个包含任意类型元素的任意类型化数组对象(typedArray) (比如 Int32Array)作为参数时,typeArray被复制到一个新的类型数组。typeArray中的每个值会在复制到新的数组之前根据构造器进行转化.新的生成的类型化数组对象将会有跟传入的数组相同的length(译者注:比如原来的typeArray.length==2,那么新生成的数组的length也是2,只是数组中的每一项进行了转化)

3.new TypedArray(object); 

object
当传入一个 object 作为参数时,如同通过 TypedArray.from() 方法一样创建一个新的类型数组。

4.new TypedArray(buffer [, byteOffset [, length]]);
//最常见用法,byteOffset、length是字节数

buffer[, byteOffset, length]
当传入arrayBuffer和可选参数byteOffset,可选参数length时,一个新的类型化数组视图将会被创建,该类型化数组视图用于呈现传入的ArrayBuffer实例。byteOffset和length指定类型化数组视图暴露的内存范围,如果两者都未传入,那么整个buffer都会被呈现,如果仅仅忽略length,那么buffer中偏移(byteOffset)后剩下的buffer将会被呈现.

//MDN规定的类型
Int8Array();
Uint8Array();
Uint8ClampedArray();
Int16Array();
Uint16Array();
Int32Array();
Uint32Array();
Float32Array();
Float64Array();//但是Chakra在实现上定义如下更多的类型OBJECT_TYPE(UninitializedObject ) //未初始化时就是这种// Typed arrays that are optimized by the JIT
OBJECT_TYPE(Int8Array           )
OBJECT_TYPE(Uint8Array          )
OBJECT_TYPE(Uint8ClampedArray   )
OBJECT_TYPE(Int16Array          )
OBJECT_TYPE(Uint16Array         )
OBJECT_TYPE(Int32Array          )
OBJECT_TYPE(Uint32Array         )
OBJECT_TYPE(Float32Array        )
OBJECT_TYPE(Float64Array        )// Virtual Arrays
//Chakra中一种TypedArray对应两种OBJECT_TYPE
OBJECT_TYPE(Int8VirtualArray)
OBJECT_TYPE(Uint8VirtualArray)
OBJECT_TYPE(Uint8ClampedVirtualArray)
OBJECT_TYPE(Int16VirtualArray)
OBJECT_TYPE(Uint16VirtualArray)
OBJECT_TYPE(Int32VirtualArray)
OBJECT_TYPE(Uint32VirtualArray)
OBJECT_TYPE(Float32VirtualArray)
OBJECT_TYPE(Float64VirtualArray)//Mixed Arrays
OBJECT_TYPE(Int8MixedArray)
OBJECT_TYPE(Uint8MixedArray)
OBJECT_TYPE(Uint8ClampedMixedArray)
OBJECT_TYPE(Int16MixedArray)
OBJECT_TYPE(Uint16MixedArray)
OBJECT_TYPE(Int32MixedArray)
OBJECT_TYPE(Uint32MixedArray)
OBJECT_TYPE(Float32MixedArray)
OBJECT_TYPE(Float64MixedArray)// Typed arrays that are not optimized by the JIT
OBJECT_TYPE(Int64Array)
OBJECT_TYPE(Uint64Array)
OBJECT_TYPE(BoolArray)
OBJECT_TYPE(CharArray)// SIMD_JS
// SIMD并不是TypedArray,但是与TypedArray在一起处理
// Only Simd128 sub-types. Currently no need to track top Simd128 type
OBJECT_TYPE(Simd128Float32x4    )
OBJECT_TYPE(Simd128Int32x4      )
OBJECT_TYPE(Simd128Int16x8      )
OBJECT_TYPE(Simd128Int8x16      )
OBJECT_TYPE(Simd128Uint32x4     )
OBJECT_TYPE(Simd128Uint16x8     )
OBJECT_TYPE(Simd128Uint8x16     )
OBJECT_TYPE(Simd128Bool32x4     )
OBJECT_TYPE(Simd128Bool16x8     )
OBJECT_TYPE(Simd128Bool8x16     )
OBJECT_TYPE(Simd128Float64x2    ) // !! This is a marker for last SIMD type. Insert new SIMD types above.

二.正文

var tst = new Uint32Array(0x10000);

1.TypedArray<>::NewInstance

率先执行到

template <typename TypeName, bool clamped, bool virtualAllocated>
Var TypedArray<TypeName, clamped, virtualAllocated>::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)

TypedArray类是一个template <typename TypeName, bool clamped, bool virtualAllocated>模版类
如此设计是为了TypeName可以指定不同的种类如Uint32Int16

TypedArray<>::NewInstance是一个public static方法,提供外部调用创建TypedArray

public:static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);

TypedArray::NewInstance上来首先获取ScriptContextThreadContext

Var TypedArray<TypeName, clamped, virtualAllocated>::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
{function->GetScriptContext()->GetThreadContext()->ProbeStack(Js::Constants::MinStackDefault, function->GetScriptContext());ARGUMENTS(args, callInfo);ScriptContext* scriptContext = function->GetScriptContext();

ThreadContext
ThreadContext在CreateRuntimeCore里,我们可以看到,在创建JsrtRuntime之前我们需要创建一个ThreadContext,而主要的初始化都是在ThreadContext上进行的。在ThreadContext里面,我们还可以看到比JsrtRuntime多得多的成员变量,并且有很多我们都非常感兴趣,比如:

  • 和内存管理相关的Recycler,各种Page Allocator * 和控制流相关的异常信息 * 各种统计信息
    我们马上会提到的JsrtContext的主要实现——ScriptContext的列表
    ……等等

可以看出,上面我们提到的Runtime提供的主要功能基本都在ThreadContext里面,可以说它是JsrtRuntime的主要实现。而通过代码我们可以看得到,JsrtRuntime和ThreadContext是一对一的,所以在读ChakraCore的代码时,我们基本可以把他们认为是一个东西。

ScriptContext
虽然在ScriptContext并没有直接被JsrtContext所持有,而是放在了JavascriptLibrary之中,但是我们还是先来看看这个类,因为这个类其实更加重要也更加的靠上层。
在JsrtContext的构造函数里面,我们可以看到第一步就是创建ScriptContext,而在销毁JsrtContext时,其主要做的事情也是由ScriptContext来完成的,可见ScriptContext其实就是JsrtContext的真实实现。(其实看名字我们也看的出来……)
还记得JsrtContext提供的功能么?在ScriptContext中,我们都可以在其成员变量中找到踪迹:

  • globalObject:这个就是浏览器里JavaScript中的window变量。
    url:当前ScriptContext的创建者的URL。
    sourceList:用于储存每个ScriptContext中加载的代码。

之后传递TypedArray<>::Create函数指针进入TypedArrayBase::CreateNewInstance

Var object = TypedArrayBase::CreateNewInstance(args, scriptContext, sizeof(TypeName), TypedArray<TypeName, clamped, virtualAllocated>::Create);

2.TypedArrayBase::CreateNewInstance

static Var CreateNewInstance(Arguments& args, ScriptContext* scriptContext, uint32 elementSize, PFNCreateTypedArray pfnCreateTypedArray );

第一次进入TypedArrayBase::CreateNewInstance时,arrayBuffer为空。因此会执行
scriptContext->GetLibrary()->CreateArrayBuffer(byteLength)

if (arrayBuffer != nullptr)
{}
else
{// Null arrayBuffer - could be new constructor or copy constructor.byteLength = elementCount * elementSize;arrayBuffer = scriptContext->GetLibrary()->CreateArrayBuffer(byteLength);
}

其中前两次的函数调用
scriptContext ScriptContext
GetLibrary() JavascriptLibrary
最后的CreateArrayBuffer函数,是从JavascriptLibrary中调用的
ArrayBuffer* JavascriptLibrary::CreateArrayBuffer(uint32 length)
这个函数是
JavascriptArrayBuffer::Create
的简单封装。

3.JavascriptArrayBuffer::Create

JavascriptArrayBuffer* JavascriptArrayBuffer::Create(uint32 length, DynamicType * type)
{Recycler* recycler = type->GetScriptContext()->GetRecycler();JavascriptArrayBuffer* result = RecyclerNewFinalized(recycler, JavascriptArrayBuffer, length, type);Assert(result);recycler->AddExternalMemoryUsage(length);return result;}

函数在通过ScriptContext获取到Memory:Recycler之后调用了RecyclerNewFinalized
RecyclerNewFinalized函数内部则调用了经过重载的new运算符,如下

template <typename TAllocator>
_Ret_notnull_
NO_EXPORT(void *) __cdecl
operator new(DECLSPEC_GUARD_OVERFLOW size_t byteSize, TAllocator * alloc, char * (TAllocator::*AllocFunc)(size_t))
{AssertCanHandleOutOfMemory();Assert(byteSize != 0);void * buffer = (alloc->*AllocFunc)(byteSize);Assume(buffer != nullptr);return buffer;
}

这里分配了72个字节,使用的是custom heap的内存管理,分配出来的是JavascriptArrayBuffer对象。new在分配了内存之后开始调用JavascriptArrayBuffer的构造函数。
经过一系列构造函数的继承关系后,最后会调用到ArrayBuffer::ArrayBuffer()
这个函数传递了lengthallocator两参数,最后调用buffer = (BYTE*)allocator(length)

template <class Allocator>ArrayBuffer::ArrayBuffer(uint32 length, DynamicType * type, Allocator allocator) :ArrayBufferBase(type){buffer = nullptr;bufferLength = 0;if (length > MaxArrayBufferLength){JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_FunctionArgument_Invalid);}else if (length > 0){Recycler* recycler = GetType()->GetLibrary()->GetRecycler();if (recycler->ReportExternalMemoryAllocation(length)){buffer = (BYTE*)allocator(length);if (buffer == nullptr){recycler->ReportExternalMemoryFree(length);}}if (buffer == nullptr){recycler->CollectNow<CollectOnTypedArrayAllocation>();if (recycler->ReportExternalMemoryAllocation(length)){buffer = (BYTE*)allocator(length);if (buffer == nullptr){recycler->ReportExternalMemoryFailure(length);}}}if (buffer != nullptr){bufferLength = length;ZeroMemory(buffer, bufferLength);}else{JavascriptError::ThrowOutOfMemoryError(GetScriptContext());}}}

注意这里的构造函数是这样进行传参的

JavascriptArrayBuffer::JavascriptArrayBuffer(uint32 length, DynamicType * type) :ArrayBuffer(length, type, IsValidVirtualBufferLength(length) ? AsmJsVirtualAllocator : malloc){}

AsmJsVirtualAllocator是一个宏

#define AsmJsVirtualAllocator ((AllocWrapperType)Js::ArrayBuffer::AllocWrapper<MAX_ASMJS_ARRAYBUFFER_LENGTH>)

跟进buffer = (BYTE*)allocator(length)之后会进入AllocWrapper这个函数

template<size_t MaxVirtualSize = MAX_ASMJS_ARRAYBUFFER_LENGTH>
static void* __cdecl AllocWrapper(DECLSPEC_GUARD_OVERFLOW size_t length)
{LPVOID address = VirtualAlloc(nullptr, MaxVirtualSize, MEM_RESERVE, PAGE_NOACCESS);//throw out of memoryif (!address){return nullptr;}if (length == 0){return address;}LPVOID arrayAddress = VirtualAlloc(address, length, MEM_COMMIT, PAGE_READWRITE);if (!arrayAddress){VirtualFree(address, 0, MEM_RELEASE);return nullptr;}return arrayAddress;
}#define MAX_ASMJS_ARRAYBUFFER_LENGTH 0x100000000 // 4GB

注意这个函数两次调用了VirtualAlloc,第一次是RESERVE,第二次是COMMIT。分配的思路就是无论申请多大内存,只要满足VirtualArray的范围那么就RESERVE 4GB的地址空间,之后再有需要多少直接COMMIT就可以了。
之后再跳回到ArrayBuffer::ArrayBuffer中,执行ZeroMemory清空分配出来的内存。
这里实现的是VirtualBuffer的分配

if (buffer != nullptr)
{bufferLength = length;ZeroMemory(buffer, bufferLength);
}

4.TypedArray<>::Create

在经过上面的一系列分配之后,执行流程返回到TypedArrayBase::CreateNewInstance函数中去。
之后在TypedArrayBase::CreateNewInstance函数中执行了如下流程

byteLength = elementCount * elementSize;    if (mappedLength == -1)
{mappedLength = (byteLength - offset)/elementSize;
}// Create and set the array based on the source.
TypedArrayBase* newArray  = static_cast<TypedArrayBase*>(pfnCreateTypedArray(arrayBuffer, offset, mappedLength, scriptContext->GetLibrary()));

mappedLength也就是等于byteLength,之后在调用pfnCreateTypedArray函数时传递了之前创建的arrayBuffer

arrayBuffer = scriptContext->GetLibrary()->CreateArrayBuffer(byteLength);

分配出来的arrayBuffer是 ArrayBufferBase*,在后面可以看到ArrayBufferBase对象是建立TypedArray的基础

pfnCreateTypedArray其实是

template <typename TypeName, bool clamped, bool virtualAllocated>
Var TypedArray<TypeName, clamped, virtualAllocated>::Create(ArrayBufferBase* arrayBuffer, uint32 byteOffSet, uint32 mappedLength, JavascriptLibrary* javascriptLibrary)

首先计算mappedByteLength=元素个数*单个元素尺寸,然后计算totalLength=byteOffSet+mappedByteLength

if (UInt32Math::Mul(mappedLength, sizeof(TypeName), &mappedByteLength) ||UInt32Math::Add(byteOffSet, mappedByteLength, &totalLength) ||(totalLength > arrayBuffer->GetByteLength()))

之后依然是调用RecyclerNew来分配内存,这个函数依然会调用重载后的new运算符分配64个字节,分配出的内存作为TypedArray view对象

 DynamicType *type = javascriptLibrary->GetTypedArrayType<TypeName, clamped>(0);return RecyclerNew(javascriptLibrary->GetRecycler(), TypedArray, arrayBuffer, byteOffSet, mappedLength, type)

5.TypedArray<>::TypedArray

在new分配了TypedArray对象的内存后,就调用它的构造函数

template <typename TypeName, bool clamped, bool virtualAllocated>
TypedArray<TypeName, clamped, virtualAllocated>::TypedArray(ArrayBufferBase* arrayBuffer, uint32 byteOffset, uint32 mappedLength, DynamicType* type) :TypedArrayBase(arrayBuffer, byteOffset, mappedLength, sizeof(TypeName), type)

依据不同的Typed类型来设置属性

switch (type->GetTypeId())
{case TypeIds_Int8Array:VirtualTableInfo<Int8VirtualArray>::SetVirtualTable(this);break;case TypeIds_Uint8Array:VirtualTableInfo<Uint8VirtualArray>::SetVirtualTable(this);break;case TypeIds_Uint8ClampedArray:VirtualTableInfo<Uint8ClampedVirtualArray>::SetVirtualTable(this);break;case TypeIds_Int16Array:VirtualTableInfo<Int16VirtualArray>::SetVirtualTable(this);break;case TypeIds_Uint16Array:VirtualTableInfo<Uint16VirtualArray>::SetVirtualTable(this);break;case TypeIds_Int32Array:VirtualTableInfo<Int32VirtualArray>::SetVirtualTable(this);break;case TypeIds_Uint32Array:VirtualTableInfo<Uint32VirtualArray>::SetVirtualTable(this);break;case TypeIds_Float32Array:VirtualTableInfo<Float32VirtualArray>::SetVirtualTable(this);break;case TypeIds_Float64Array:VirtualTableInfo<Float64VirtualArray>::SetVirtualTable(this);break;default:break;
}

最后返回的是TypedArray*的指针,至此TypedArray创建成功

对象继承关系

JavascriptArrayBuffer:
ArrayBuffer:
ArrayBufferBase:
DynamicObject:
RecyclableObject:
FinalizableObject

调用总览
1.创建JavascriptArrayBuffer对象
2.创建Virtual Buffer
3.创建TypedArray对象

Virtual buffer创建流程

kernel32.dll!VirtualAlloc
ChakraCore.dll!Js::ArrayBufferBase::AllocWrapper<4294967296>()
ChakraCore.dll!Js::ArrayBuffer::ArrayBuffer<void * __ptr64 (__cdecl*)(unsigned __int64)>()
ChakraCore.dll!Js::JavascriptArrayBuffer::JavascriptArrayBuffer()
ChakraCore.dll!Js::JavascriptArrayBuffer::Create()
ChakraCore.dll!Js::JavascriptLibrary::CreateArrayBuffer()
ChakraCore.dll!Js::TypedArrayBase::CreateNewInstance()
ChakraCore.dll!Js::TypedArray<unsigned int,0,0>::NewInstance()
ChakraCore.dll!amd64_CallFunction()

TypedArray创建流程

ChakraCore.dll!Memory::Recycler::AllocWithAttributesInlined<0,0>()
ChakraCore.dll!Memory::Recycler::AllocInlined(unsigned __int64 size)
ChakraCore.dll!operator new<Memory::Recycler>()
ChakraCore.dll!Js::TypedArray<unsigned int,0,0>::Create()
ChakraCore.dll!Js::TypedArrayBase::CreateNewInstance()
ChakraCore.dll!Js::TypedArray<unsigned int,0,0>::NewInstance()
ChakraCore.dll!amd64_CallFunction() 

JavascriptArrayBuffer创建流程

ChakraCore.dll!Js::JavascriptArrayBuffer::Create()
ChakraCore.dll!Js::JavascriptLibrary::CreateArrayBuffer()
ChakraCore.dll!Js::TypedArrayBase::CreateNewInstance()
ChakraCore.dll!Js::TypedArray<unsigned int,0,0>::NewInstance()
ChakraCore.dll!amd64_CallFunction()

转载于:https://www.cnblogs.com/Ox9A82/p/7308360.html

Chakra调试笔记 TypedArray相关推荐

  1. 调试笔记--jlink 变量转实时波形小技巧

    调试笔记–jlink 变量转实时波形小技巧 上篇讲了jlink RTT组件在RAM中开辟一段内存,将printf字符串存入然后通过jlink调试接口读取RAM,将printf字符串在jlink-RTT ...

  2. 调试笔记--keil 测量周期小技巧

    调试笔记–keil 测量周期小技巧 本文参考安富莱专题教程第7期 http://www.armbbs.cn/forum.php?mod=viewthread&tid=87176&ext ...

  3. 调试笔记--keil 断点调试小技巧

    调试笔记–keil 断点调试小技巧 给变量打断点 调试不熟悉的项目时,卧槽!怎么这么多全局变量?这玩意又在那修改了??这个时候会给变量打断点就能省好多事. 将要监视的全局变量添加到watch窗口 选中 ...

  4. gpio驱动广播Android,[RK3288][Android6.0] 调试笔记 --- 通用GPIO驱动控制LED【转】

    Platform: ROCKCHIP OS: Android 6.0 Kernel: 3.10.92 由于板子没有lcd无法得知sd卡升级是否完成,因此使用LED显示. Recovery中升级完成后控 ...

  5. keil4怎么移植其他人的程序_【调试笔记】韦东山:在100ask_imx6ull上移植使用六轴传感器ICM20608...

    之前发了LCD调试笔记,大家很感兴趣,所以这次再来一篇:六轴传感器ICM20608驱动移植笔记,大家还需要什么移植笔记?可以留言.我们尽量满足. 1.1 移植思路 先找到驱动:也许内核里已经有,也许需 ...

  6. RK3399 GT1X触摸屏驱动调试笔记

    硬件环境 1.Firefly AIO-3399(AI)开发版: 2.恒智的5寸电容触摸屏800X480,I2C驱动支持GT5688. 操作系统 Android 7.2 for rockship Ste ...

  7. Rockchip基于RK3566/RK3568 WiFi AP6256调试笔记

    1.开发平台 CPU:RK3566 编译环境:Ubuntu18.04 内核版本:kernel 4.19 2.目的 因为RK3566/RK3568支持SDIO3.0并且向下兼有SDIO2.0接口,由于核 ...

  8. 雅马哈四轴机器人调试笔记

    雅马哈四轴机器人调试笔记 1.0 先简单说下硬件,如下图对着插就行,雅马哈四轴主要硬件有控制器跟机械手,机械手到控制器主要有4跟电机接口电缆,每2个轴有一个编码器接口电缆,每根轴有一个配置的数据备份电 ...

  9. OMAP3530-mini调试笔记(2)

    PS:USB不能正常工作的根本原因参见调试笔记(3) 各个版本的x-loader和u-boot对kernel的支持情况: U-Boot 2011.12-00010-ga3eb89c (Jan 29 2 ...

最新文章

  1. AI系列一:机器学习介绍
  2. java 报表导出_Java Excel报表导出Demo
  3. 剑指 Offer 05. 替换空格 简单
  4. 若谷歌实用量子计算机难产,拉里·佩奇会把它砍掉吗?
  5. 基础知识收藏(ASP.NET的OnClientClick与OnClick事件)-2013.07.10
  6. 致北漂——你来北京不是为了配合出演苦情戏
  7. mysql中rpl_MySQL管理工具MySQL Utilities — mysqlrplcheck(44)
  8. 福昕熊雨前:PDFium开源项目的背后
  9. 虚拟服务器设置 - 百度,百度云虚拟主机BCH配置伪静态图文教学
  10. java a =a-=aa_java 初学 :求 s=a+aa+aaa+aaaa+aa...a 的值,其中 a 是一个数字。几个 数相加由键盘控制。...
  11. [5-21]绿色精品软件每天更新[uc23整理]
  12. _ie6png图片的修复
  13. windows聚焦壁纸不更新_锁屏壁纸windows聚焦不更新?
  14. 一文彻底解决 matplotlib 中的字体管理
  15. freyja2多数据源版本
  16. 英文论文有具体的格式吗?
  17. 服务器被恶意攻击可以报警吗?
  18. [Android Studio]掌握Android Studio的五种常见控件和五种常见布局
  19. python读json文件json.decoder.JSONDecodeError终极解决大法
  20. 玩转无线路由DD-WRT特色功能

热门文章

  1. Android家长老师家校校园通(IDEA开发,后台管理,前台app)
  2. matlab中字符表示,(专题一)07 matlab中字符串的表示
  3. matlab查找鞍点的位置,找出一个二维数组中的鞍点,即该位置上的元素在该行上最大、在该...
  4. Linux进程调度-CFS调度器原理分析及实现,懂了
  5. DTO(数据传输对象)模式
  6. android+桌面歌词,【Android】桌面歌词悬浮效果简单实现
  7. php设置 uploadtmpdir_关于PHP上传文件时配置 php.ini 中的 upload_tmp_dir
  8. 下载微信服务器上的图片到自己的服务器
  9. [应用交流]Excel鲜为人知的35招秘技
  10. 英伟达登录界面卡住_免费!Google Colab现已支持英伟达T4 GPU