integer advertisement inwards C

Screen_Shot_2017-08-03_at_2.08_.20_PM_.p

Loup Vaillant wrote a expert weblog post nearly his novel crypto library Monocypher.

In spite of the obvious tilt of launching a novel crypto library, I truly similar it. Note that this is non me officially endorsing the library, I but retrieve it's cool together with I would alone consider using it later it had matured a chip more.

The whole affair is i ,1500LOC file together with is pretty clear to read. It alone implements a few crypto functions.

The weblog post service mentions a few bugs that were constitute inwards his library (and I appreciate how opened upwards he is nearly it). Here's an interesting one:

Bug 5: signed integer overflow
This i was sneaky. I wouldn't convey caught it without UBSan.
I was shifting a uint8_t, 24 bits to the left. I failed to realise that integer advertisement agency this unsigned byte would endure converted to a signed integer, together with overflow if the byte exceeded 127. (Also, on crazy platforms where integers are smaller than 32 bits, this would never convey worked.) An explicit conversion to uint32_t did the trick.
At this point, I was running the diverse sanitisers but to growth confidence. Since I used Valgrind already, I didn't hold back to truly grab a bug. Good affair I did it anyway.
Lesson learned: Never drive anything serious inwards C or C++ without sanitisers. They're non but for theatrics, they grab existent bugs.

This is the problem patched.

patch

Simplified, the bad code truly looks similar this:

  uint32_t = uint8_t << viii * i;  

And all the theory behind the employment tin endure dismissed, if he had written his code amongst precautions. When I run into something similar this, the get-go affair I retrieve nearly is that it should belike endure written similar this:

  uint32_t = (uint32_t)uint8_t << viii * i;  

This would avoid whatsoever weird C problems equally a casting (especially to a bigger type) commonly goes fine.

OK but what was the employment amongst the higher upwards code?

Well, inwards C around operations volition commonly promote the type to something bigger. See the C standard:

shift-expression << additive-expression
The integer promotions are performed on each of the operands

What is an integer promotion? See the C standard:

If an int tin stand upwards for all values of the master copy type, the value is converted to an int;
otherwise, it is converted to an unsigned int.
These are called the integer promotions

So looking dorsum at our bad snippet:

  uint32_t = uint8_t << viii * i;  
  1. the uint8_t value is converted to an int. Holding the same value inwards bits but inwards 16-bit or 32-bit depending on the architecture. So 01 would endure 00 00 00 01 if an int is 32-bit.
  2. the bits are shifted on the left. For representative of viii places 00 00 01 00
  3. the upshot gets casted to uint32_t. We even together with then acquire 00 00 01 00.

This doesn't seem similar an issue, together with it belike isn't most of the time. Now imagine if inwards 1. our value was 80 (which is 1000 0000 inwards bits).

Imagine straight off that inwards 2. nosotros shift it of 24 bits on the left, that volition hand us 80 00 00 00 which is an all null bitstring except for the most pregnant chip (MSB). In an int type the MSB is the signing bit. I believe at this point, the value volition endure automatically sign extended to the size of the register, together with then inwards your 64-bit machine it volition endure saved equally ff ff ff ff lxxx 00 00 00.

Now inwards 3. The upshot straight off acquire casted to a uint32_t. Which doesn't create anything but alter the value of the pointer. But nosotros straight off convey a incorrect result! What nosotros wanted hither was 00 00 00 00 lxxx 00 00 00. If you're non convinced, you lot tin run the next script on your computer:

  #include <stdio.h>    #include <stdint.h>        int main(){        uint8_t start = -1;    printf("%x\n", start); // prints 0xff    uint64_t upshot = start << 24;    printf("%llx\n", result); // should impress 00000000ff000000, but volition impress ffffffffff000000    upshot = (uint64_t)start << 24;    printf("%llx\n", result); // prints 00000000ff000000    provide 0;    }  

Looking at the binary inwards Hopper nosotros tin run into this:

reverse

And nosotros bring out the movsxd didactics which is "move doubleword to quadword amongst sign-extension"


[Telegram Channel | Original Article: ]