Skip to content

std::fs::File::read incorrectly mapps EOPNOTSUPP (95) to ErrorKind::Uncategorized #139803

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
krzysiek4321 opened this issue Apr 14, 2025 · 2 comments · Fixed by #139822
Closed
Labels
A-error-handling Area: Error handling A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` C-bug Category: This is a bug. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. O-unix Operating system: Unix-like T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@krzysiek4321
Copy link

Below is a lot of code because to replicate the bug you need to have an amdgpu that has at least one sensor not implemented. For me its RX 6700 XT and it has 7 unsupported sensors. You can probably also replicate it by using another kernel module that can return EOPNOTSUPP or write your own.

Replace <N> with your amdgpu number, probably 0

I tried this code:

use std::fs::File;
use std::io::{ErrorKind, Read, Seek};

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub enum AmdPpSensors {
    AmdgpuPpSensorGfxSclk = 0,
    AmdgpuPpSensorCpuClk,
    AmdgpuPpSensorVddnb,
    AmdgpuPpSensorVddgfx,
    AmdgpuPpSensorUvdVclk,
    AmdgpuPpSensorUvdDclk,
    AmdgpuPpSensorVceEcclk,
    AmdgpuPpSensorGpuLoad,
    AmdgpuPpSensorMemLoad,
    AmdgpuPpSensorGfxMclk,
    AmdgpuPpSensorGpuTemp,
    //AmdgpuPpSensorEdgeTemp = 10, // Same as AmdgpuPpSensorGpuTemp
    AmdgpuPpSensorHotspotTemp,
    AmdgpuPpSensorMemTemp,
    AmdgpuPpSensorVcePower,
    AmdgpuPpSensorUvdPower,
    AmdgpuPpSensorGpuAvgPower,
    AmdgpuPpSensorGpuInputPower,
    AmdgpuPpSensorSsApuShare,
    AmdgpuPpSensorSsDgpuShare,
    AmdgpuPpSensorStablePstateSclk,
    AmdgpuPpSensorStablePstateMclk,
    AmdgpuPpSensorEnabledSmcFeaturesMask,
    AmdgpuPpSensorMinFanRpm,
    AmdgpuPpSensorMaxFanRpm,
    AmdgpuPpSensorVcnPowerState,
    AmdgpuPpSensorPeakPstateSclk,
    AmdgpuPpSensorPeakPstateMclk,
    AmdgpuPpSensorVcnLoad,
}
const AMDGPU_PP_SENSORS: usize = 28; // TODO: This value should not be hardcoded, but derived
impl AmdPpSensors {
    pub const ALL_VARIANTS: [Self; AMDGPU_PP_SENSORS] = [
        Self::AmdgpuPpSensorGfxSclk,
        Self::AmdgpuPpSensorCpuClk,
        Self::AmdgpuPpSensorVddnb,
        Self::AmdgpuPpSensorVddgfx,
        Self::AmdgpuPpSensorUvdVclk,
        Self::AmdgpuPpSensorUvdDclk,
        Self::AmdgpuPpSensorVceEcclk,
        Self::AmdgpuPpSensorGpuLoad,
        Self::AmdgpuPpSensorMemLoad,
        Self::AmdgpuPpSensorGfxMclk,
        Self::AmdgpuPpSensorGpuTemp,
        Self::AmdgpuPpSensorHotspotTemp,
        Self::AmdgpuPpSensorMemTemp,
        Self::AmdgpuPpSensorVcePower,
        Self::AmdgpuPpSensorUvdPower,
        Self::AmdgpuPpSensorGpuAvgPower,
        Self::AmdgpuPpSensorGpuInputPower,
        Self::AmdgpuPpSensorSsApuShare,
        Self::AmdgpuPpSensorSsDgpuShare,
        Self::AmdgpuPpSensorStablePstateSclk,
        Self::AmdgpuPpSensorStablePstateMclk,
        Self::AmdgpuPpSensorEnabledSmcFeaturesMask,
        Self::AmdgpuPpSensorMinFanRpm,
        Self::AmdgpuPpSensorMaxFanRpm,
        Self::AmdgpuPpSensorVcnPowerState,
        Self::AmdgpuPpSensorPeakPstateSclk,
        Self::AmdgpuPpSensorPeakPstateMclk,
        Self::AmdgpuPpSensorVcnLoad,
    ];
}

fn main() -> () {
    let path = "/sys/kernel/debug/dri/<N>/amdgpu_sensors";

    let mut file = File::open(path).expect("Opening this file");

    let mut supported_variants: [u8; AMDGPU_PP_SENSORS] = [0u8; AMDGPU_PP_SENSORS];
    let mut buf = [0u8; 16];
    for size in [0, 4, 8] {
        for (variant, variant_size) in supported_variants
            .iter_mut()
            .enumerate()
            .filter(|&(_, &mut variant_size)| variant_size == size)
        {
            let view = &mut buf[..size as usize + 4];
            let _ = file
                .seek(std::io::SeekFrom::Start(variant as u64 * 4))
                .expect("Seek to succeed, since I used an amdgpu enum variant. (as of 2025-04-14)");
            let red = file.read_exact(view);
            match red {
                Ok(_) => *variant_size += 4,
                Err(e) => match e.kind() {
                    ErrorKind::InvalidInput => (),
                    ErrorKind::Unsupported => (),
                    _ => eprintln!("{:?}: {:?}", variant, e),
                },
            }
        }
    }
}

I expected to see this happen: Nothing gets printed since I ran this program as root and catch expected errors. According to amdgpu kernel module source code EINV and EOPNOTSUPP are expected.

Instead, this happened:

1: Os { code: 95, kind: Uncategorized, message: "Operation not supported" }
[...]

Meta

rustc --version --verbose:

rustc 1.86.0 (05f9846f8 2025-03-31) (Fedora 1.86.0-1.fc41)
binary: rustc
commit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb
commit-date: 2025-03-31
host: x86_64-unknown-linux-gnu
release: 1.86.0
LLVM version: 19.1.7
rustc 1.88.0-nightly (092a284ba 2025-04-13)
binary: rustc
commit-hash: 092a284ba0421695f2032c947765429fd7095796
commit-date: 2025-04-13
host: x86_64-unknown-linux-gnu
release: 1.88.0-nightly
@krzysiek4321 krzysiek4321 added the C-bug Category: This is a bug. label Apr 14, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 14, 2025
@ShE3py
Copy link
Contributor

ShE3py commented Apr 14, 2025

Minimized:

use std::io::{self, ErrorKind};

fn main() {
    assert_eq!(io::Error::from_raw_os_error(libc::EOPNOTSUPP /* 95 */).kind(), ErrorKind::Unsupported);
    //^ currently `ErrorKind::Uncategorized`, should be `ErrorKind::Unsupported`
}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
use ErrorKind::*;
match errno as libc::c_int {
libc::E2BIG => ArgumentListTooLong,
libc::EADDRINUSE => AddrInUse,
libc::EADDRNOTAVAIL => AddrNotAvailable,
libc::EBUSY => ResourceBusy,
libc::ECONNABORTED => ConnectionAborted,
libc::ECONNREFUSED => ConnectionRefused,
libc::ECONNRESET => ConnectionReset,
libc::EDEADLK => Deadlock,
libc::EDQUOT => QuotaExceeded,
libc::EEXIST => AlreadyExists,
libc::EFBIG => FileTooLarge,
libc::EHOSTUNREACH => HostUnreachable,
libc::EINTR => Interrupted,
libc::EINVAL => InvalidInput,
libc::EISDIR => IsADirectory,
libc::ELOOP => FilesystemLoop,
libc::ENOENT => NotFound,
libc::ENOMEM => OutOfMemory,
libc::ENOSPC => StorageFull,
libc::ENOSYS => Unsupported,
libc::EMLINK => TooManyLinks,
libc::ENAMETOOLONG => InvalidFilename,
libc::ENETDOWN => NetworkDown,
libc::ENETUNREACH => NetworkUnreachable,
libc::ENOTCONN => NotConnected,
libc::ENOTDIR => NotADirectory,
#[cfg(not(target_os = "aix"))]
libc::ENOTEMPTY => DirectoryNotEmpty,
libc::EPIPE => BrokenPipe,
libc::EROFS => ReadOnlyFilesystem,
libc::ESPIPE => NotSeekable,
libc::ESTALE => StaleNetworkFileHandle,
libc::ETIMEDOUT => TimedOut,
libc::ETXTBSY => ExecutableFileBusy,
libc::EXDEV => CrossesDevices,
libc::EINPROGRESS => InProgress,
libc::EACCES | libc::EPERM => PermissionDenied,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
_ => Uncategorized,
}
}

@rustbot label +T-libs +A-error-handling +E-easy +O-unix

@rustbot rustbot added A-error-handling Area: Error handling E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. O-unix Operating system: Unix-like T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Apr 14, 2025
@bjorn3
Copy link
Member

bjorn3 commented Apr 14, 2025

It is technically not incorrect, just incomplete. ErrorKind::Uncategorized is the catch-all error kind for errors that haven't been categorized behind another ErrorKind variant yet.

@lolbinarycat lolbinarycat added A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 14, 2025
Zalathar added a commit to Zalathar/rust that referenced this issue Apr 15, 2025
…tolnay

Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix

This change maps the EOPNOTSUPP errno value (95) to std::io::ErrorKind::Unsupported in the decode_error_kind function for Unix platforms. Previously, it was incorrectly mapped to ErrorKind::Uncategorized.

Fixes rust-lang#139803
Zalathar added a commit to Zalathar/rust that referenced this issue Apr 15, 2025
…tolnay

Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix

This change maps the EOPNOTSUPP errno value (95) to std::io::ErrorKind::Unsupported in the decode_error_kind function for Unix platforms. Previously, it was incorrectly mapped to ErrorKind::Uncategorized.

Fixes rust-lang#139803
@bors bors closed this as completed in 188d44d Apr 15, 2025
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Apr 15, 2025
Rollup merge of rust-lang#139822 - 0x79de:fix-eopnotsupp-mapping, r=dtolnay

Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix

This change maps the EOPNOTSUPP errno value (95) to std::io::ErrorKind::Unsupported in the decode_error_kind function for Unix platforms. Previously, it was incorrectly mapped to ErrorKind::Uncategorized.

Fixes rust-lang#139803
github-actions bot pushed a commit to model-checking/verify-rust-std that referenced this issue Apr 19, 2025
This change maps the EOPNOTSUPP errno value (95) to std::io::ErrorKind::Unsupported in the decode_error_kind function for Unix platforms. Previously, it was incorrectly mapped to ErrorKind::Uncategorized.

Fixes rust-lang#139803
github-actions bot pushed a commit to model-checking/verify-rust-std that referenced this issue Apr 19, 2025
…tolnay

Fix: Map EOPNOTSUPP to ErrorKind::Unsupported on Unix

This change maps the EOPNOTSUPP errno value (95) to std::io::ErrorKind::Unsupported in the decode_error_kind function for Unix platforms. Previously, it was incorrectly mapped to ErrorKind::Uncategorized.

Fixes rust-lang#139803
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-error-handling Area: Error handling A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` C-bug Category: This is a bug. E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. O-unix Operating system: Unix-like T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants