Skip to content

std::io::Write panics when write calls return negative values with larger absolute value than 4095.  #142909

Open
@artiepoole

Description

@artiepoole

Writing to /sys/class/fpga_manager/fpga*/firmware when driver's firmware write fails and causes a panic. The std::io::Write call mishandles an IO error from the system when interfacing with a hardware driver's virtual file in Linux (Ubuntu 24.04). The atypical error codes returned by the driver are mishandled in rust, but work as expected in other languages such as python (and bash).

I tried this code (as sudo):

use std::io::Write;
use std::fs::OpenOptions;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
    let control_path = "/sys/class/fpga_manager/fpga0/firmware";
    let f = OpenOptions::new()
        .create(false)
        .read(false)
        .write(true)
        .open(control_path)?;
    write!(&f, "blank.bit.bin")?;
    Ok(())
}

I expected to see this happen:

In this case, the blank.bit.bin is an invalid bitstream for the FPGA and so the write should return an error.

The kernel logs show:

fpga_manager fpga0: writing blank.bit.bin to Xilinx ZynqMP FPGA Manager
fpga_manager fpga0: Error while writing image data to FPGA

as expected, so the write is happening and completes.

In bash, this is done as:

$ echo "blank.bit.bin" | sudo tee -a /sys/class/fpga_manager/fpga0/firmware 

which does not panic, but does return error code 1: No such file or directory
(which is not correct, but that's not relevant).

The error code reported by the driver is stored in /sys/class/fpga_manager/fpga0/state and is
write error: 0xffffe5fe. I believe that this value is what is mishandled in Rust.

The write should return an Err of type Err(std::io::Error) as the Result when encountering this error code.

I wrote this C application to do the same operation and it may explain the issue:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(void) {
    int fd = open("/sys/class/fpga_manager/fpga0/firmware", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    const char *data = "blank.bit.bin";
    ssize_t res = write(fd, data, strlen(data));

    if (res == -1) {
        perror("write");
    } else {
        printf("Wrote %zd bytes\n", res);
    }

    if (close(fd) == -1) {
        perror("close");
    }

    return 0;
}

will print

Wrote -6658 bytes

which leads me to suspect that to the error code printed:

range start index 18446744073709544958 out of range for slice of length 13

is caused by not handling the negative return value safely.

For your convenience:

18446744073709544958 = 0xFFFFFFFFFFFFE5FE
-6658 = 0xFFFFE5FE
18446744073709544958 + 6658 = 0

Instead, this happened:

The kernel panicked. Instead of returning the error code, the slice is indexed incorrectly, and causes a panic during slice_start_index_len_fail. The stack traces is included below.

Meta

rustc --version --verbose:

rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: aarch64-unknown-linux-gnu
release: 1.87.0
LLVM version: 20.1.1

full strace output: https://pastebin.com/rvaBZZhe

Backtrace

$ sudo RUST_LOG=trace RUST_BACKTRACE=full ~/fpgad/target/debug/fpgad

thread 'main' panicked at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/io/mod.rs:1801:36:
range start index 18446744073709544958 out of range for slice of length 13
stack backtrace:
   0:     0xc6788f6b6dd4 - std::backtrace_rs::backtrace::libunwind::trace::h7503a148b50af80e
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/../../backtrace/src/backtrace/libunwind.rs:117:9
   1:     0xc6788f6b6dd4 - std::backtrace_rs::backtrace::trace_unsynchronized::h53bbad37af4a0c96
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/../../backtrace/src/backtrace/mod.rs:66:14
   2:     0xc6788f6b6dd4 - std::sys::backtrace::_print_fmt::hd99d24ec073b8939
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/sys/backtrace.rs:66:9
   3:     0xc6788f6b6dd4 - <std::sys::backtrace::BacktraceLock::print::DisplayBacktrace as core::fmt::Display>::fmt::h1fbe53ada150180d
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/sys/backtrace.rs:39:26
   4:     0xc6788f6d0bcc - core::fmt::rt::Argument::fmt::h049d7aecf8048234
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/fmt/rt.rs:184:76
   5:     0xc6788f6d0bcc - core::fmt::write::h5b94da46a291b015
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/fmt/mod.rs:1481:21
   6:     0xc6788f6b4ee8 - std::io::default_write_fmt::h7afd8f861709d185
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/io/mod.rs:639:11
   7:     0xc6788f6b4ee8 - std::io::Write::write_fmt::hec377ff9de3cf70a
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/io/mod.rs:1914:13
   8:     0xc6788f6b6c88 - std::sys::backtrace::BacktraceLock::print::hb027b8167acd80fb
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/sys/backtrace.rs:42:9
   9:     0xc6788f6b7b04 - std::panicking::default_hook::{{closure}}::hfad582597c3f1f0b
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:300:22
  10:     0xc6788f6b795c - std::panicking::default_hook::h89691caec866c0de
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:327:9
  11:     0xc6788f6b83d0 - std::panicking::rust_panic_with_hook::h09fd228ea89637cb
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:833:13
  12:     0xc6788f6b8230 - std::panicking::begin_panic_handler::{{closure}}::h27e0e6e387396050
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:706:13
  13:     0xc6788f6b72c8 - std::sys::backtrace::__rust_end_short_backtrace::h1396474dff16dbe5
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/sys/backtrace.rs:168:18
  14:     0xc6788f6b7ee0 - __rustc[95feac21a9532783]::rust_begin_unwind
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:697:5
  15:     0xc6788f696098 - core::panicking::panic_fmt::h2784ce5f3242d97e
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/panicking.rs:75:14
  16:     0xc6788f6965b8 - core::slice::index::slice_start_index_len_fail::do_panic::runtime::h2ad90a17f7f28956
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/panic.rs:218:21
  17:     0xc6788f6963a4 - core::slice::index::slice_start_index_len_fail::do_panic::hbedd6cc2a2234b45
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/intrinsics/mod.rs:3241:9
  18:     0xc6788f6963a4 - core::slice::index::slice_start_index_len_fail::h0f3d6e6b29b55e99
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/panic.rs:223:9
  19:     0xc6788f699e2c - <core::ops::range::RangeFrom<usize> as core::slice::index::SliceIndex<[T]>>::index::h7a4c4512053479f6
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/slice/index.rs:561:13
  20:     0xc6788f698064 - core::slice::index::<impl core::ops::index::Index<I> for [T]>::index::h99ee48726c6e993f
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/slice/index.rs:16:9
  21:     0xc6788f698064 - std::io::Write::write_all::h25e43cf9727ad31a
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/io/mod.rs:1801:36
  22:     0xc6788f697768 - <std::io::default_write_fmt::Adapter<T> as core::fmt::Write>::write_str::hea1b4cdcf8ad26b9
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/io/mod.rs:628:19
  23:     0xc6788f6d0c18 - core::fmt::write::h5b94da46a291b015
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/fmt/mod.rs:1506:9
  24:     0xc6788f697478 - std::io::default_write_fmt::h488cd17643e5f163
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/io/mod.rs:639:11
  25:     0xc6788f697ba0 - std::io::Write::write_fmt::hef83df5134388249
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/io/mod.rs:1914:13
  26:     0xc6788f6971c4 - fpgad::main::h0196210e57a4dc4e
                               at /home/ubuntu/fpgad/WS0er33ydC/src/main.rs:59:5
  27:     0xc6788f696904 - core::ops::function::FnOnce::call_once::hb22d96a71eaebd12
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/ops/function.rs:250:5
  28:     0xc6788f69686c - std::sys::backtrace::__rust_begin_short_backtrace::hf8c79057dadb648f
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/sys/backtrace.rs:152:18
  29:     0xc6788f696cb8 - std::rt::lang_start::{{closure}}::h40bb393ddedb5aed
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/rt.rs:199:18
  30:     0xc6788f6b2144 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::hd800098b0508cfaa
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/core/src/ops/function.rs:284:13
  31:     0xc6788f6b2144 - std::panicking::try::do_call::he73c8963fb5ba50b
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:589:40
  32:     0xc6788f6b2144 - std::panicking::try::h26b8f5da2b75e384
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:552:19
  33:     0xc6788f6b2144 - std::panic::catch_unwind::h4efc10d799add92b
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panic.rs:359:14
  34:     0xc6788f6b2144 - std::rt::lang_start_internal::{{closure}}::ha387644324cd6b0d
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/rt.rs:168:24
  35:     0xc6788f6b2144 - std::panicking::try::do_call::ha3a74b6e4c2f30bd
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:589:40
  36:     0xc6788f6b2144 - std::panicking::try::h6c715ec6edd04ab6
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panicking.rs:552:19
  37:     0xc6788f6b2144 - std::panic::catch_unwind::h299af3710728a70e
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/panic.rs:359:14
  38:     0xc6788f6b2144 - std::rt::lang_start_internal::h1e2ca5c47444f14a
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/rt.rs:164:5
  39:     0xc6788f696c94 - std::rt::lang_start::h078039403035c0d9
                               at /rustc/17067e9ac6d7ecb70e50f92c1944e545188d2359/library/std/src/rt.rs:198:5
  40:     0xc6788f697290 - main
  41:     0xeb507b1784c4 - <unknown>
  42:     0xeb507b178598 - __libc_start_main
  43:     0xc6788f6966f0 - _start
  44:                0x0 - <unknown>

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ioArea: `std::io`, `std::fs`, `std::net` and `std::path`C-external-bugCategory: issue that is caused by bugs in software beyond our controlO-linuxOperating system: LinuxT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions