[coreutils] dd failed to print trailing new line


coreutils-7.5 (fixed in 7.6)

How to reproduce?

1.creat a file named test1, input string “1234567890dddch”

2. coreutils-7.5/src/dd  cbs=6  conv=unblock  if=test1 of=test.bak


dd is a program to copy a file after converting and formatting according to the operands.

In the example above:

coreutils-7.5/src/dd  cbs=6  conv=unblock  if=test1 of=test.bak

‘cbs=BYTES’ tells dd to convert BYTES bytes at a time. So each time dd converts a cbs-sized chunk, ending with a new line. ‘conv=unblock’ tells dd to replace trailing spaces in cbs-sized with new line. So if the last cbs-sized chunk is not full, then dd should add a new line.

Therefore, the output “test.bak” should be




[new line]


The output test.bak produced by the buggy dd is:





Root cause:

The computation of the condition to print the final ‘\n’ was incorrect. The function dd_copy() should print a final '\n' if the last line does not have sufficient characters. But in version 7.5 (buggy version),  only if there are exactly `conversion_blocksize' characters, the '\n' is added in output.

Comments written by us are in blue.

dd_copy() {

    /* ‘col’ is a global index, pointing to the next available byte

     * in the current cbs-sized chunk.

     * In the buggy case, there were 3 bytes remaining in the

     * last chunk, so col=4 (next byte).


     * It indicates the length of the last chunk

     * is not multiple of cbs-size, so in this case, output(newline)

     * was not called.


     * In other words, the logic is totally messed up.

     * Any execution with ‘cbs’ and ‘conv’ will produce incorrect

     * result!


-    if ((conversions_mask & C_UNBLOCK) && col == conversion_blocksize)

+    if (col && (conversions_mask & C_UNBLOCK))

        /* Add a final '\n' if there are exactly `conversion_blocksize'

            characters in the final record. */

        output_char (newline_character);

Is there Error Message?


Can Errlog insert a message?

No. This error condition is subtle, and actually the fault/error/failure are in the same location. If we can log the error, then why don’t we just fix the bug?