Почему в этом коде значение под указателем перезаписывается?
Я пытаюсь разобраться с 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. Неправильное использование указателей: В языке программирования C/C++ указатели могут быть сложными для понимания и использования правильно. Если вы не корректно используете указатели, это может привести к перезаписи значений. Убедитесь, что вы правильно выделяете память, разыменовываете указатели и освобождаете память после использования.
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; // освобождение памяти
3. Некорректное использование указателей на стеке: Если вы объявляете указатель на стеке и пытаетесь вернуть его из функции, это может привести к ошибке, так как память указателя может быть освобождена после выхода из функции.
int* func() { int value = 10; int* ptr = &value; // указатель на переменную на стеке return ptr; // возвращение указателя на стеке }
Чтобы избежать перезаписи значения под указателем, убедитесь, что вы правильно используете указатели, следите за работой с памятью и избегайте некорректных операций. При возникновении проблемы, рекомендуется тщательно проверить код и убедиться в его корректности.