@arms/rum-reactnative 0.1.3-beta.0 → 0.1.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -191,7 +191,7 @@ static void emit_frame(int fd, char *buf, size_t *pos,
191
191
 
192
192
  int si = rum_module_index_for_addr(addr);
193
193
  if (si >= 0) {
194
- uintptr_t base = rum_seg_load_base(si);
194
+ uintptr_t base = rum_module_base_for_seg(si);
195
195
 
196
196
  // 记录被引用模块的 image_addr(去重),供 binary_images 过滤
197
197
  if (base != 0 && *referenced_count < MAX_REFERENCED_MODULES) {
@@ -316,6 +316,9 @@ void rum_write_crash(int fd, int signum, siginfo_t *info, ucontext_t *uc,
316
316
 
317
317
  // 解析 /proc/self/maps(async-signal-safe),为帧提供模块归属与相对偏移
318
318
  rum_modules_parse();
319
+ // 构建去重模块列表,供 emit_frame 获取模块级基址和 binary_images 枚举使用。
320
+ // 必须在 frames 循环前调用,确保 rum_module_base_for_seg() 能查到模块。
321
+ int mod_count = rum_module_build_distinct();
319
322
 
320
323
  // binary_images 按需过滤:仅保留被栈帧引用的模块。
321
324
  // 参照 Sentry 实践,服务端符号化时忽略未被任何栈帧引用的模块,
@@ -328,36 +331,28 @@ void rum_write_crash(int fd, int signum, siginfo_t *info, ucontext_t *uc,
328
331
  // "frames":[{"address","library","image_addr","offset"}, ...]
329
332
  // library/offset 供后端结合 binary_images 的 build_id 精确符号化
330
333
  //
331
- // 双侧截断(参照 Sentry 推荐方案):frame_count 达到 TRUNCATION_THRESHOLD(512)
332
- // 时说明实际栈可能更长(信号处理器中只能采集前 MAX_FRAMES 帧)。此时保留
333
- // 前 FRAMES_PER_SIDE 帧和后 FRAMES_PER_SIDE 帧,中间插入标记帧。
334
- // 注意:NDK 信号处理器只能获取前 512 帧,无法获取真正的"后 256 帧"
335
- // (靠近 main 的帧),omitted_count=-1 表示实际总帧数未知。
334
+ // NDK 信号处理器最多采集 MAX_FRAMES(512) 帧。frame_count 达到
335
+ // TRUNCATION_THRESHOLD(512) 时说明实际栈可能更长(已达到采集上限),
336
+ // 此时全部输出 512 帧 + 尾部标记帧(omitted_count=-1 表示实际总帧数
337
+ // 未知),不做双侧截断——因为 NDK 只能获取前 512 帧,前 256 + 后 256
338
+ // 恰好覆盖全部 512 帧,中间无省略,插入中间标记帧会造成冗余。
336
339
  // frame_count < TRUNCATION_THRESHOLD 时全部输出,不截断。
337
340
  // 所有操作仅为栈上数组读写与整数比较,符合 async-signal-safe。
338
341
  buf_append(fd, buf, &pos, ",\"frames\":[");
339
- int needs_truncation = (frame_count >= TRUNCATION_THRESHOLD);
342
+ int needs_tail_marker = (frame_count >= TRUNCATION_THRESHOLD);
340
343
  int first = 1;
341
344
 
342
- int head_count = needs_truncation ? FRAMES_PER_SIDE : frame_count;
343
- for (int i = 0; i < head_count; i++) {
345
+ for (int i = 0; i < frame_count; i++) {
344
346
  emit_frame(fd, buf, &pos, (uintptr_t)frames[i],
345
347
  referenced_addrs, &referenced_count, &first);
346
348
  }
347
349
 
348
- if (needs_truncation) {
349
- // 截断标记帧(omitted_count=-1 表示实际总帧数未知)
350
+ if (needs_tail_marker) {
351
+ // 尾部标记帧(omitted_count=-1 表示实际总帧数未知)
350
352
  if (!first) {
351
353
  buf_append(fd, buf, &pos, ",");
352
354
  }
353
355
  buf_append(fd, buf, &pos, "{\"truncated\":true,\"omitted_count\":-1}");
354
- first = 0;
355
-
356
- int tail_start = frame_count - FRAMES_PER_SIDE;
357
- for (int i = tail_start; i < frame_count; i++) {
358
- emit_frame(fd, buf, &pos, (uintptr_t)frames[i],
359
- referenced_addrs, &referenced_count, &first);
360
- }
361
356
  }
362
357
  buf_append(fd, buf, &pos, "]");
363
358
 
@@ -375,7 +370,6 @@ void rum_write_crash(int fd, int signum, siginfo_t *info, ucontext_t *uc,
375
370
  // 仅上报带 GNU build-id 的 file-backed 模块(build-id 等价于 iOS image uuid,
376
371
  // 用于后端精确匹配符号文件)。
377
372
  buf_append(fd, buf, &pos, ",\"binary_images\":[");
378
- int mod_count = rum_module_build_distinct();
379
373
  int emitted = 0;
380
374
  char bid[BUILD_ID_HEX_CAP];
381
375
  for (int m = 0; m < mod_count; m++) {
@@ -152,6 +152,27 @@ uintptr_t rum_seg_load_base(int seg_index) {
152
152
  return g_segs[seg_index].start - g_segs[seg_index].offset;
153
153
  }
154
154
 
155
+ uintptr_t rum_module_base_for_seg(int seg_index) {
156
+ if (seg_index < 0 || seg_index >= g_seg_count) {
157
+ return 0;
158
+ }
159
+ // 查找该段所属模块(同路径),返回模块级基址(image_addr)。
160
+ // 与 binary_images 的 rum_module_image_addr() 一致,确保 emit_frame
161
+ // 收集的 referenced_addrs 与 binary_images 过滤比较的基址相同。
162
+ // 若 rum_module_build_distinct() 尚未调用(g_mod_count == 0),
163
+ // 回退到段级基址。
164
+ const char *path = g_segs[seg_index].path;
165
+ int path_len = g_segs[seg_index].path_len;
166
+ for (int m = 0; m < g_mod_count; m++) {
167
+ if (g_mods[m].path_len == path_len &&
168
+ memcmp(g_mods[m].path, path, (size_t)path_len) == 0) {
169
+ return g_mods[m].image_addr;
170
+ }
171
+ }
172
+ // Fallback: 段级基址
173
+ return g_segs[seg_index].start - g_segs[seg_index].offset;
174
+ }
175
+
155
176
  const char *rum_seg_path(int seg_index, int *out_len) {
156
177
  if (seg_index < 0 || seg_index >= g_seg_count) {
157
178
  if (out_len) *out_len = 0;
@@ -296,6 +317,24 @@ int rum_module_build_id_hex(uintptr_t load_base, char *out, int out_cap) {
296
317
  const unsigned char *name = note + sizeof(ElfW(Nhdr));
297
318
  const unsigned char *desc = name + ((namesz + 3u) & ~3u);
298
319
 
320
+ // 边界检查:确保 name 区域不超出 note section。
321
+ // 损坏的 namesz 可导致 name 指针越界,memcmp 读取未映射内存
322
+ // 触发二次 SIGSEGV。
323
+ if (name + namesz > note_end) {
324
+ break;
325
+ }
326
+
327
+ // 边界检查:desc 起始地址(含对齐填充)不得超出 note section。
328
+ if (desc > note_end) {
329
+ break;
330
+ }
331
+
332
+ // 边界检查:将 descsz clamp 到实际可用范围,防止 desc[b] 循环
333
+ // 读取超出 note section 的内存,触发二次 SIGSEGV。
334
+ if (desc + descsz > note_end) {
335
+ descsz = (uint32_t)(note_end - desc);
336
+ }
337
+
299
338
  if (type == NT_GNU_BUILD_ID && namesz == 4 &&
300
339
  memcmp(name, "GNU", 4) == 0) {
301
340
  static const char hexc[] = "0123456789abcdef";
@@ -24,6 +24,10 @@ int rum_module_index_for_addr(uintptr_t addr);
24
24
  /** 段的加载基址(= start - file_offset)。索引非法返回 0。 */
25
25
  uintptr_t rum_seg_load_base(int seg_index);
26
26
 
27
+ /** 段所属模块的加载基址(模块级 image_addr,与 binary_images 一致)。
28
+ * 需在 rum_module_build_distinct() 之后调用;未构建时回退到段级基址。 */
29
+ uintptr_t rum_module_base_for_seg(int seg_index);
30
+
27
31
  /** 段对应的模块路径(指向内部缓冲,非 null 结尾)。out_len 输出长度。 */
28
32
  const char *rum_seg_path(int seg_index, int *out_len);
29
33
 
@@ -119,6 +119,9 @@ function formatStack(frames) {
119
119
  // 截断标记帧:双侧截断时插入的中间标记
120
120
  if (frame.truncated) {
121
121
  const count = frame.omitted_count ?? -1;
122
+ if (count < 0) {
123
+ return `#${index} ... frames omitted (unknown count) ...`;
124
+ }
122
125
  return `#${index} ... ${count} frames omitted ...`;
123
126
  }
124
127
  const library = frame.library || '<unknown>';
@@ -14,7 +14,7 @@ var _rumCore = require("@arms/rum-core");
14
14
  var _reactNative = require("react-native");
15
15
  var _NativeRumSdkReactnative = _interopRequireDefault(require("../NativeRumSdkReactnative"));
16
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
- const _pkg = {"version":"0.1.3-beta.0"};
17
+ const _pkg = {"version":"0.1.3-beta.1"};
18
18
  const VERSION = exports.VERSION = _pkg.version;
19
19
 
20
20
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -114,6 +114,9 @@ function formatStack(frames) {
114
114
  // 截断标记帧:双侧截断时插入的中间标记
115
115
  if (frame.truncated) {
116
116
  const count = frame.omitted_count ?? -1;
117
+ if (count < 0) {
118
+ return `#${index} ... frames omitted (unknown count) ...`;
119
+ }
117
120
  return `#${index} ... ${count} frames omitted ...`;
118
121
  }
119
122
  const library = frame.library || '<unknown>';
@@ -3,7 +3,7 @@
3
3
  import { AppType } from '@arms/rum-core';
4
4
  import { Dimensions, Platform } from 'react-native';
5
5
  import NativeRumSdkReactnative from "../NativeRumSdkReactnative.js";
6
- const _pkg = {"version":"0.1.3-beta.0"};
6
+ const _pkg = {"version":"0.1.3-beta.1"};
7
7
  export const VERSION = _pkg.version;
8
8
 
9
9
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arms/rum-reactnative",
3
- "version": "0.1.3-beta.0",
3
+ "version": "0.1.3-beta.1",
4
4
  "description": "RUM SDK For ReactNative",
5
5
  "homepage": "https://help.aliyun.com/zh/arms/user-experience-monitoring/",
6
6
  "main": "./lib/commonjs/index.js",