Rust 中 实现 Js 字符串方法 常用 Trait - 数组越界 之 程序安全
/// usize 是 自然数 也就是说 整数 抛去负数
/// i32 是 整数 一些 js 调用方法索引传 负数是有奇效的 详情见 chrome console
pub trait StringExtend {
fn charCodeAt(&self, index: usize) -> Option<u32>;
fn charAt(&self, index: Option<i32>) -> Option<String>;
fn indexOf(&self, findchar: &str, fromindex: Option<usize>) -> i32;
fn slice(&self, fromindex: i32) -> String;
fn substr(&self, fromindex: i32, length: Option<i32>) -> String;
}
返回指定索引Unicode编码 charCodeAt
- code
impl StringExtend for String {
fn charCodeAt(&self, index: Option<usize>) -> Option<u32> {
let safe_index = index.unwrap_or(0);
let charlist: Vec<char> = self.chars().collect::<Vec<char>>();
charlist.get(safe_index).map(|val| *val as u32)
}
}
返回指定索引字符 charAt
- code
impl StringExtend for String {
fn charAt(&self, index: Option<i32>) -> Option<String> {
let safe_index = index.unwrap_or(0);
if safe_index < 0 {
return Some("".to_string());
}
let charlist: Vec<char> = self.chars().collect::<Vec<char>>();
charlist.get(safe_index as usize).map(|val| val.to_string())
}
}
查找第一次指定字符 在字符串中索引位置,indexOf
-
注意: 若查找不到返回-1 (i32),可选参数是 指定开始查找索引位置 默认为 0 第一个字符串开始
-
code
impl StringExtend for String {
fn indexOf(&self, findchar: &str, fromindex: Option<usize>) -> i32 {
let list = self.chars().into_iter().map(|x| x.to_string()).collect::<Vec<String>>();
let len = list.len();
let mut res = -1;
let start = fromindex.unwrap_or(0);
if start > len - 1 {
return res;
}
let mut index = start;
let step = findchar.len();
loop {
let search_start = index;
let mut search_end = index + step;
if search_end > len - 1 {
search_end = len - 1;
}
if index < len {
let mut cc = "".to_string();
list[search_start..search_end].iter().for_each(|x| {
cc += x.as_str();
});
if cc.as_str() == findchar {
res = index as i32;
break;
}
} else {
break;
}
index += 1;
}
res
}
}
指定位置进行字符串切片 slice
-
注意: js的位置是可以传负数实现的,这里不是简单的 rust slice 切片可以实现的!
-
注意: js默认不传是返回字符串本身(暂未实现)
-
code
impl StringExtend for String {
fn slice(&self, fromindex: i32) -> String {
let len = self.len() as i32;
if fromindex > len {
return "".to_string();
}
return if fromindex >= 0 {
self.clone().as_str()[fromindex as usize..].to_string()
} else {
let mut rev_start = len + fromindex;
if rev_start < 0 {
rev_start = 0;
}
self.clone().as_str()[rev_start as usize..].to_string()
};
}
}
指定位置,指定长度进行字符串切片 substr
-
注意: js 同样2个参数 都可以传负数 返回的结果是安全 而非 panic
-
注意: js默认不传是返回字符串本身(暂未实现)
-
code
impl StringExtend for String {
fn substr(&self, fromindex: i32, length: Option<i32>) -> String {
let len = self.len() as i32;
if length.is_some() && length.unwrap() <= 0 {
return "".to_string();
}
if fromindex >= len {
return "".to_string();
}
return if fromindex < 0 {
self.slice(fromindex)
} else {
let start = fromindex as usize;
let end = if let Some(length_val) = length {
(fromindex + length_val) as usize
} else {
len as usize
};
self.clone().as_str()[start..end].to_string()
};
}
}
-
通过上述所有实现我们发现在 JS 实现之处就设计了 很多 index 索引 上下越界安全的情况,为什么呢。
-
结论: ->
-
数组越界向下 “诡异” 堆上内存信息为空无法被其他程序 快速定位填充,但可以在循环体中 可以被 自己程序上 其他变量堆上的信息 被暂时修改,导致诡异行为。
-
数组越界向上 “危险” 修改 堆上 的 return 指针 可以在堆上 被替代 导致黑客注入 自己程序的指针信息 恶意利用