Как исправить SIGSEGV в этой простой реализации двусвязного списка? - PullRequest
0 голосов
/ 14 апреля 2019

Я получаю ошибку SIGSEGV при запуске этого кода.

Код компилируется, отладчик показывает, что выглядит как случайные адреса в указателях.

use std::ptr;

pub struct List<T> {
    head: *mut Node<T>,
    tail: *mut Node<T>,
}

struct Node<T> {
    data: Option<T>,
    next: *mut Node<T>,
    prev: *mut Node<T>,
}

impl<T> List<T> {
    pub fn new() -> Self {
        Self {
            head: ptr::null_mut(),
            tail: ptr::null_mut(),
        }
    }
    pub fn add_tail(&mut self, data: T) {
        let mut new_node = Box::new(Node {
            data: Some(data),
            next: ptr::null_mut(),
            prev: ptr::null_mut(),
        });
        let new_node_ptr: *mut Node<T> = &mut *new_node;
        if self.tail.is_null() {
            self.head = new_node_ptr;
        } else {
            new_node.next = self.tail;
            unsafe {
                (*self.tail).prev = new_node_ptr;
            }
        }
        self.tail = new_node_ptr;
    }
    pub fn remove_tail(&mut self) -> Option<T> {
        if self.tail.is_null() {
            None
        } else {
            let old_tail_ptr = self.tail;
            unsafe {
                if (*old_tail_ptr).next.is_null() {
                    self.tail = ptr::null_mut();
                    self.head = ptr::null_mut();
                } else {
                    let new_tail_ptr = (*old_tail_ptr).next;
                    (*old_tail_ptr).next = ptr::null_mut();
                    (*new_tail_ptr).prev = ptr::null_mut();
                    self.tail = new_tail_ptr;
                }
                (*old_tail_ptr).data.take()
            }
        }
    }
}

Мой тест добавляет десять целых чисел 0..9, и они выталкивают их. На второй поп я получаю

сигнал: 11, SIGSEGV: недопустимая ссылка на память.

1 Ответ

1 голос
/ 15 апреля 2019

Следующее исправит ошибку.В add_tail:

  • заменить let new_node_ptr: *mut Node<T> = &mut *new_node; на let new_node_ptr = Box::into_raw(new_node);
  • заменить new_node.next = self.tail на (*new_node_ptr).next = self.tail;
  • включить (*new_node_ptr).next = self.tail; в unsafe block

Ошибка произошла из-за неправильного получения базового указателя из ящика.

После let new_node_ptr: *mut Node<T> = &mut *new_node; Box продолжал управлять памятью, на которую указывает new_node_ptr.В конце блока Box освобождает память автоматически, оставляя new_node_ptr висячим.

Чтобы получить указатель с ручным управлением памятью и освободить управление памятью из Box, используйте Box::into_raw вместо &mut *.

...