Почему в этом коде значение под указателем перезаписывается?

Ссылка скопирована
1 ответ

Я пытаюсь разобраться с epoll. У меня есть некий EventData

pub struct EventData {     pub fd: RawFd, }

pub struct EventData { pub fd: RawFd, }

И есть некий selector, который имеет методы add_fd и select.

#[inline(always)]     pub fn select(&self, events: &mut [EpollEvent], wait: Option<u64>) -> io::Result<Option<u64>> {         let timeout_ms = wait             .map(|to| EpollTimeout::try_from(ns_to_ms(to)).unwrap())             .unwrap_or(EpollTimeout::NONE);                  let n = self.selector.epoll.wait(events, timeout_ms)?;          for event in unsafe { events.get_unchecked_mut(..n) } {             if event.data() == 0 {                 // this is just a wakeup event, ignore it                 let mut buf = [0u8; 8];                 // clear the event_fd, ignore the result                 read(self.selector.event_fd.as_raw_fd(), &mut buf).ok();                 continue;             }             let data = unsafe { ptr::read(event.data() as *mut ManuallyDrop<EventData>) };              println!("event: {}",  data.fd);         }          if n == 0 {             // zero events, so we can sleep             Ok(None)         } else if n < 64{             Ok(Some(1_000_000))         } else {             // n >= 64, so we can call epoll again immediately, because it has enough events             Ok(Some(0))         }     }          #[inline(always)]     pub fn add_fd(&self, fd: RawFd) -> nix::Result<()> {         let data = new_event_data(fd, None);         let md = ManuallyDrop::new(data);         let info = EpollEvent::new(             EpollFlags::EPOLLIN                 | EpollFlags::EPOLLOUT                 | EpollFlags::EPOLLRDHUP                 | EpollFlags::EPOLLET,             &md as *const _ as u64,         );          self.selector.epoll.add(unsafe { BorrowedFd::borrow_raw(fd) }, info)     }

#[inline(always)] pub fn select(&self, events: &mut [EpollEvent], wait: Option<u64>) -> io::Result<Option<u64>> { let timeout_ms = wait .map(|to| EpollTimeout::try_from(ns_to_ms(to)).unwrap()) .unwrap_or(EpollTimeout::NONE); let n = self.selector.epoll.wait(events, timeout_ms)?; for event in unsafe { events.get_unchecked_mut(..n) } { if event.data() == 0 { // this is just a wakeup event, ignore it let mut buf = [0u8; 8]; // clear the event_fd, ignore the result read(self.selector.event_fd.as_raw_fd(), &mut buf).ok(); continue; } let data = unsafe { ptr::read(event.data() as *mut ManuallyDrop<EventData>) }; println!("event: {}", data.fd); } if n == 0 { // zero events, so we can sleep Ok(None) } else if n < 64{ Ok(Some(1_000_000)) } else { // n >= 64, so we can call epoll again immediately, because it has enough events Ok(Some(0)) } } #[inline(always)] pub fn add_fd(&self, fd: RawFd) -> nix::Result<()> { let data = new_event_data(fd, None); let md = ManuallyDrop::new(data); let info = EpollEvent::new( EpollFlags::EPOLLIN | EpollFlags::EPOLLOUT | EpollFlags::EPOLLRDHUP | EpollFlags::EPOLLET, &md as *const _ as u64, ); self.selector.epoll.add(unsafe { BorrowedFd::borrow_raw(fd) }, info) }

Я ожидаю, что получу свой EventData в select и уже там его очищу. Проблема в том, что я получаю не то значение fd, которое кладу.

EventData никогда не очищается и никогда не перезаписывается (select вызывается строго последовательно). Почему я не получаю свой fd? (в этом коде используется библиотека nix)

Дополнительно:

Произошла какая-то магия, когда я решил вывести на экран в функции создания.
println!("data fd: {}, must be {fd}", data.fd);
После этого код внезапно заработал. Я попробовал вместо вывода использовать black_box, я снова поймал ошибку. У меня нет идей, с чем связана эта магия, и такой костыль меня не устраивает. Есть идеи?

Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Сергей Миронов Ответ

Проблема, когда значение под указателем перезаписывается, может возникать из-за нескольких причин. Давайте рассмотрим некоторые из них и способы их решения.

1. Неправильное использование указателей: В языке программирования C/C++ указатели могут быть сложными для понимания и использования правильно. Если вы не корректно используете указатели, это может привести к перезаписи значений. Убедитесь, что вы правильно выделяете память, разыменовываете указатели и освобождаете память после использования.

int* ptr = new int; // выделение памяти для указателя
*ptr = 10; // присваивание значения по адресу, на который указывает указатель
delete ptr; // освобождение памяти

int* ptr = new int; // выделение памяти для указателя *ptr = 10; // присваивание значения по адресу, на который указывает указатель delete ptr; // освобождение памяти

2. Некорректная работа с памятью: Если вы работаете с динамической памятью, необходимо следить за выделением и освобождением памяти. Перезапись значения может произойти, если вы обращаетесь к памяти, которая уже была освобождена или если происходит выход за границы выделенной памяти.

int* arr = new int[5]; // выделение памяти под массив из 5 элементов
for (int i = 0; i < 5; i++) {
  arr[i] = i; // присваивание значений элементам массива
}
delete[] arr; // освобождение памяти

int* arr = new int[5]; // выделение памяти под массив из 5 элементов for (int i = 0; i < 5; i++) { arr[i] = i; // присваивание значений элементам массива } delete[] arr; // освобождение памяти

3. Некорректное использование указателей на стеке: Если вы объявляете указатель на стеке и пытаетесь вернуть его из функции, это может привести к ошибке, так как память указателя может быть освобождена после выхода из функции.

int* func() {
  int value = 10;
  int* ptr = &value; // указатель на переменную на стеке
  return ptr; // возвращение указателя на стеке
}

int* func() { int value = 10; int* ptr = &value; // указатель на переменную на стеке return ptr; // возвращение указателя на стеке }

Чтобы избежать перезаписи значения под указателем, убедитесь, что вы правильно используете указатели, следите за работой с памятью и избегайте некорректных операций. При возникновении проблемы, рекомендуется тщательно проверить код и убедиться в его корректности.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно