Subject: bug#6417: [Bug 591969] Re: dd bs=3G || ubuntu-bug coreutils

From: Jim Meyering <[email-masked]>
Date: Sun, 13 Jun 2010 21:19:46 +0200

Dave Gilbert wrote:
> You're on 32bit, on 64bit this seems to work.  My guess is that there is
> a limit to the block size available on 32bit (if that limit was 2G or
> just under it wouldn't surprise me), on 64bit there is a similar limit
> somewhere :
>
> dg@major:~$ true | dd bs=3G count=1
> 0+0 records in
> 0+0 records out
> 0 bytes (0 B) copied, 2.1008e-05 s, 0.0 kB/s
> dg@major:~$ true | dd bs=3E count=1
> dd: memory exhausted
> dg@major:~$ true | dd bs=3Z count=1
> dd: invalid number `3Z'
>
> I can see an argument that there might want to put a better error message in, or state that the bs is dependent on memory
> size.

Thanks for the report.

dd is trying to tell you not to specify such a large buffer size.
A buffer size larger than a few megabytes is not normally useful.

That diagnostic is not helpful indeed, but it was easy to fix,
so I'll probably apply something like the following upstream.
With the new diagnostic, you can see that dd tries (and fails)
to allocate output buffers of the specified size:

    $ :|./dd bs=3EiB
    ./dd: failed to allocate an input buffer of size 3.0 EiB
    [Exit 1]
    $ :|./dd obs=3EiB
    ./dd: failed to allocate an output buffer of size 3.0 EiB
    [Exit 1]

Making dd give a better diagnostic for e.g., "bs=3G" on an i686
system might be more work than it's worth.

>From 899f17359bf4990888b54c5ae90c41a74529d04d Mon Sep 17 00:00:00 2001
From: Jim Meyering <[email-masked]>
Date: Sun, 13 Jun 2010 17:34:45 +0200
Subject: [PATCH] dd: print a better diagnostic for an invalid block size
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* src/dd.c (dd_copy): Give a better diagnostic than
"dd: memory exhausted" for an over-large bs= block size setting.
Same for ibs= and obs=.  Reported by Imre Péntek in
http://bugs.launchpad.net/ubuntu/+source/coreutils/+bug/591969
---
 src/dd.c |   25 +++++++++++++++++++++++--
 1 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/src/dd.c b/src/dd.c
index 30d3d28..c9b8cbd 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -1557,6 +1557,16 @@ set_fd_flags (int fd, int add_flags, char const *name)
     }
 }

+static char *
+human_size (size_t n)
+{
+  static char hbuf[LONGEST_HUMAN_READABLE + 1];
+  int human_opts =
+    (human_autoscale | human_round_to_nearest | human_base_1024
+     | human_space_before_unit | human_SI | human_B);
+  return human_readable (n, hbuf, human_opts, 1, 1);
+}
+
 /* The main loop.  */

 static int
@@ -1593,7 +1603,13 @@ dd_copy (void)
      It is necessary when accessing raw (i.e. character special) disk
      devices on Unixware or other SVR4-derived system.  */

-  real_buf = xmalloc (input_blocksize + INPUT_BLOCK_SLOP);
+  size_t sz = input_blocksize + INPUT_BLOCK_SLOP;
+  real_buf = malloc (sz);
+  if (!real_buf)
+    error (EXIT_FAILURE, 0,
+           _("failed to allocate an input buffer of size %s"),
+           human_size (sz));
+
   ibuf = real_buf;
   ibuf += SWAB_ALIGN_OFFSET;	/* allow space for swab */

@@ -1602,7 +1618,12 @@ dd_copy (void)
   if (conversions_mask & C_TWOBUFS)
     {
       /* Page-align the output buffer, too.  */
-      real_obuf = xmalloc (output_blocksize + OUTPUT_BLOCK_SLOP);
+      sz = output_blocksize + OUTPUT_BLOCK_SLOP;
+      real_obuf = malloc (sz);
+      if (!real_obuf)
+        error (EXIT_FAILURE, 0,
+               _("failed to allocate an output buffer of size %s"),
+               human_size (sz));
       obuf = ptr_align (real_obuf, page_size);
     }
   else
--
1.7.1.511.g2f531