coreutils-7.5 (fixed in 7.6)
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
123456
7890dd
dch
[new line]
The output test.bak produced by the buggy dd is:
123456
7890dd
dch
[EOF]
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);
No.
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?