Index out of bounds


#1

I am creating a programming language for fun in Rust. Currently, I am working on an error function that underlines the given code and throws an error code.

fn error(message: &str, code: &str, mut line: Vec<String>, index: i32, file: &str){
    println!("{}{}{}: {}", "error[".red(), code.red(), "]".red(), message);
    println!(">  in {}\n|", file);
    let mut whole = "".to_string();
    for i in line.clone() {
        whole.push_str(i.as_str());
    }
    println!("|  {}...", whole.cyan());
    let mut spaces = "".to_string();
    line.pop();
    let mut j = 0;
    'spaces: while j < line.clone().len(){
        match line.get(j){
            Some(k) => {
                for l in k.chars() {
                    spaces.push_str(" ");
                }
            },
            None => break 'spaces
        }
        j = j + 1
    }
    print!("|  {}^", spaces);
    let mut arr = vec![0; line[index as usize].len()];
    for l in arr {
        print!("~")
    }
    println!("")
}

Which I am calling as error("explicitly defined private", "f1", line.clone(), index). Line is ["def", " ", "private", " ", "public"], index is 4, and file is examples/functions.surf.

This function should output

error[f1]: explicitly defined private
>  in examples/functions.surf
|
|  def private public...
|              ^~~~~~

But instead is panicking

error[f1]: explicitly defined private
>  in examples/functions.surf
|
|  def private public...
thread 'main' panicked at 'index out of bounds: the len is 4 but the index is 4', /Users/travis/build/rust-lang/rust/src/libcollections/vec.rs:1552
stack backtrace:
   0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace
   1: std::panicking::default_hook::{{closure}}
   2: std::panicking::default_hook
   3: std::panicking::rust_panic_with_hook
   4: std::panicking::begin_panic
   5: std::panicking::begin_panic_fmt
   6: rust_begin_unwind
   7: core::panicking::panic_fmt
   8: core::panicking::panic_bounds_check
   9: <collections::vec::Vec<T> as core::ops::Index<usize>>::index
  10: surf::interpreter::error
  11: surf::interpreter::interpret
  12: surf::main
  13: __rust_maybe_catch_panic
  14: std::rt::lang_start
  15: main
|              ^

Why is this so? I think every loop is written in a way the index shouldn’t go out of bounds.
(I am running cargo build with Rust 1.19.0)


#2

You have a line.pop() there.


#3

Yes, but doesn’t that modify line? Or do I need to reset it? (line = line.pop())


#4

It does modify line, but I’m not sure I follow your question:

line starts out having length = 5. The rest of that function deals with a clone of line (going to be inefficient, by the way). Then you pop off the last element - line is now length = 4. Then you do line[index as usize], but index is 4 and out of bounds now. Maybe I’m missing something?


#5

I’m sorry. Are you saying the program is panicking at line[index as usize], and not the while loop? I thought the error was coming from the while loop.


#6

Yes that’s where the error is :slight_smile:


#7

I’m sorry. I just edited my code to line[index as usize-1] and that appears to have done the trick! *smacks forehead* Thanks so much for your help!


#8

No worries. I now realize you were asking about specifically the looping being OOB - sorry, I should’ve been clearer in my first reply.


#9

No problem. Again, much thanks. :smiley:


#10

BTW, Rust unfortunately supports line numbers only on Linux :frowning:

Workaround for this on other platforms is:

lldb -- target/debug/<your executable>
b rust_panic
r
bt

This will stop the debugger and print detailed backtrace, with line numbers.


#11

Nice tip @kornel.

I’ll mention that this line in the backtrace is sort of a giveaway once one is familiar with how [] desugars:

9: <collections::vec::Vec<T> as core::ops::Index<usize>>::index

Fortunately, there’s just one occurrence of indexing a vec in that snippet :slight_smile: