Subject: Re: bug#24874: dd: misleading parsing of hex numbers

From: Jim Meyering <[email-masked]>
Date: Fri, 4 Nov 2016 13:18:55 -0500

On Fri, Nov 4, 2016 at 12:03 PM, Pádraig Brady <[email-masked]> wrote:
> On 04/11/16 16:20, Pádraig Brady wrote:
>> On 04/11/16 11:19, Stephan Bauroth wrote:
>>> Dear coreutils team :)
>>>
>>> I encountered a buglike behaviour of dd when handling skip and count
>>> parameters that are encoded in hex and thus prefixed with 0x.
>>>
>>> dd is not able to parse them, which is OK but would be great if it would
>>> be, but, worse, reads 0xf00 as 0. It does that silently. While an
>>> enduser will immediately notice this on count, since nothing is copied,
>>> behaviour for skip looks ok. (In fact, I noticed this only because I
>>> hexdumped the result after hours of debugging)
>>>
>>> While it's OK that dd can't parse these numbers, maybe there should be a
>>> warning that 0x was found and interpreted as 0. Since a char like 'x' is
>>> invalid within a number that by definition has to be decimal, a warning
>>> should be fairly easy to implement.
>>>
>>> Of course, the ability to parse hex numbers in these parameters would be
>>> awesome :)
>>>
>>> regards and thanks for your continuing work,
>>> Stephan Bauroth
>>
>> Ouch. That's a real gotcha.
>> Note hex digits after the 0x are diagnosed, but not decimal digits:
>>
>>   $ dd skip=0x100 seek=0xf00
>>   dd: invalid number: ‘0xf00’
>>
>> Disallowing 0x... could definitely break backwards compat though.
>> Consider `for rec in 0 1 2; do dd skip=${rec}x1024...`
>>
>> I suppose we could output a warning to suggest using
>>   $(($rec * $size)) or 0${rec}x${size}
>> if that really is the intention?
>>
>> Given the warning workaround would be suggested in the message,
>> and that it's a relatively rare usage, a warning is probably appropriate here.
>> We already warn in dd for various usage.
>>
>> I'll fix that for the coming release.
>
> Patch attached.

Ouch, confusing indeed. I like your solution. One nit:

- dd if=/dev/null count=0x1 seek=0x1 skip=0x1 status=none 2>err
+ dd if=/dev/null count=0x1 seek=0x1 skip=0x1 status=none 2>err || fail=1