Rust 中 实现 Js 字符串方法 常用 Trait - 数组越界 之 程序安全

213 阅读1分钟

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 索引 上下越界安全的情况,为什么呢。

  • 推荐视频 www.zhihu.com/zvideo/1444…

  • 结论: ->

  • 数组越界向下 “诡异” 堆上内存信息为空无法被其他程序 快速定位填充,但可以在循环体中 可以被 自己程序上 其他变量堆上的信息 被暂时修改,导致诡异行为。

  • 数组越界向上 “危险” 修改 堆上 的 return 指针 可以在堆上 被替代 导致黑客注入 自己程序的指针信息 恶意利用