Skip to content

EncoderWriter::write_all leads to WriteZero error #148

@paolobarbolini

Description

@paolobarbolini

Using base64::write::EncoderWriter with a writer that accepts very limited writes leads to EncoderWriter::write_all calls failing.

To reproduce (playground link)

extern crate base64; // 0.13.0

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

/// A Writer that limits how much can be written in a single call
struct ShortWriter<'a, W> {
    writer: &'a mut W,
    max_write_len: usize,
}

impl<'a, W> Write for ShortWriter<'a, W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let write_len = std::cmp::min(self.max_write_len, buf.len());
        let written = self.writer.write(&buf[..write_len])?;
        // do some other stuff...
        Ok(written)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

fn main() {
    let contents = vec![b'A'; 100];

    let mut vec = Vec::with_capacity(8196);
    {
        let writer_ = ShortWriter {
            writer: &mut vec,
            max_write_len: 76,
        };
        let mut writer = base64::write::EncoderWriter::new(writer_, base64::STANDARD);
        writer.write_all(&contents).unwrap();
    }
    
    assert_eq!(vec, base64::encode(contents).into_bytes());
}

To reproduce 2 (expanded the default Write::write_all implementation) (playground link)

Click to expand!
extern crate base64; // 0.13.0

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

/// A Writer that limits how much can be written in a single call
struct ShortWriter<'a, W> {
    writer: &'a mut W,
    max_write_len: usize,
}

impl<'a, W> Write for ShortWriter<'a, W>
where
    W: Write,
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let write_len = std::cmp::min(self.max_write_len, buf.len());
        let written = self.writer.write(&buf[..write_len])?;
        // do some other stuff...
        Ok(written)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

fn main() {
    let contents = vec![b'A'; 100];

    let mut vec = Vec::with_capacity(8196);
    {
        let writer_ = ShortWriter {
            writer: &mut vec,
            max_write_len: 76,
        };
        let mut writer = base64::write::EncoderWriter::new(writer_, base64::STANDARD);
        // writer.write_all(&contents).unwrap();
        
        let mut buf: &[u8] = contents.as_ref();
        while !buf.is_empty() {
            println!("writing");
            match writer.write(buf) {
                Ok(0) => {
                    // this should never happen
                    println!("ignoring zero write");
                }
                Ok(n) => {
                    println!("written len: {}", n);
                    buf = &buf[n..];
                },
                Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {}
                Err(e) => panic!("err: {}", e),
            }
        }
    }
    
    assert_eq!(vec, base64::encode(contents).into_bytes());
}

Expected behavior

Encoding succeeds, and the contents of vec are the same I would get if I were to call base64::encode(contents).

Observed behavior

writer.write_all(&contents) fails with Custom { kind: WriteZero, error: "failed to write whole buffer" }

Environment

rust: stable
base64: 0.13.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions