3

I was looking into structs in C when I noticed this oddity.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

struct vulnStruct {
    char start[20];
    char overflow[10];
    char *controlledPointer;
};

int main(int argc, char *argv[]){
    struct vulnStruct *test = malloc(sizeof(struct vulnStruct));
    printf("Sizeof vulnStruct: %d\r\n", sizeof(struct vulnStruct));
    printf("Sizeof start: %d\r\n", sizeof(test->start));
    printf("Sizeof overflow: %d\r\n", sizeof(test->overflow));
    printf("Sizeof controlledPointer: %d\n\r", sizeof(test->controlledPointer));
    free(test);
    return 0;
}

When compiled this program should output the sizeof the vulnStruct and its elements. Manually adding up the struct shows that it should be 38 bytes long however when this program is run it shows that the struct's size is instead 40 bytes long. At first I thought it was just padding for the struct as answered here (Size of a structure in C) however, when I add a 2 byte field (uint16_t) to the end of the struct in an attempt to fill the padding it just increases the struct by 2 bytes. Is this because the controlledPointer is being padded to 10 bytes by the compiler and won't let anything else use that space or is there something like a canary at the end that is taking up the space. If it is just padding is there anyway to arrange the elements so that the padding can be used by another field?

EDIT: It would probably help if I get the output of the program as well

Sizeof vulnStruct: 40
Sizeof start: 20
Sizeof overflow: 10
Sizeof controlledPointer: 8

Thanks in advance!

  • Try using `offsetof` to get more info. But the padding is often to align individual fields with word/dword boundaries, so adding to the end of the struct wouldn't affect the padding. – Brian Cain Mar 13 '16 at 22:34
  • The padding will be in between `overflow` and `controlledPointer`. If you add your test 2-byte field in there you should observe the size stay the same – M.M Mar 13 '16 at 22:34
  • BTW `%zu` is the format specifier for `size_t`, and you should not print `\r` (if you are in windows then the implementation will translate `\n` to `\r\n` for stdout already) – M.M Mar 13 '16 at 22:37
  • Thanks, adding the 2-byte field in the correct position did indeed not increase the size and also thanks for pointing out the return character and formatting issue. – Dexter Gerig Mar 13 '16 at 22:55

4 Answers4

2

The padding is between overflow[10]; and *controlledPointer.

The problem is that it's doing 4-byte alignment of the fields--something that almost always is worthwhile to do. Two bytes of memory is almost always cheaper than the time penalty for a non-aligned memory access.

The only cases where this would be an issue is if you're trying to match some other structure or when you have a huge number of items. Declare it accordingly in these cases. My C is too rusty to tell you how to declare it, though.

Loren Pechtel
  • 8,945
  • 3
  • 33
  • 45
  • Based on OP numbers it is probably 8-byte pointer (which may have 4-byte or 8-byte alignment, can't tell from this) – M.M Mar 13 '16 at 22:36
  • If it were 8-byte alignment there would be padding between start[20] and overflow[10]. Thus it's 4-byte alignment. – Loren Pechtel Mar 13 '16 at 23:02
  • Typically, char arrays do not have alignment requirements. You should find no size difference if changing this to `start[19]` and `overflow[11]` for example. – M.M Mar 13 '16 at 23:03
0

The problem with structures is that they have "padding" meaning that if you have 1 char in a structure the structure will MOST PROBABLY have a size of 4bytes/8bytes depending on the data bus of your processor. This is due to the fact that to optimize the access speed, when compiling the structure is padded with 0xff bytes.

There is some compilation directives which don't use padding but this is not recommended UNLESS you are programming an actual device. This can be done in gcc(the default unix compile) with the following directive but it depends on each compiler:

#pragma (push,pack 1)
//define structure(...)
#pragma (pop)

The pragma in this case has it's own stack, look at this post if you want a clearer idea on padding and the pragma directive

Community
  • 1
  • 1
Mr. Branch
  • 442
  • 2
  • 13
0

Note that your results will very much vary per target/compiler.

Here's what I get when I try to find out more about padding specifically:

$ clang -Wpadded -Wno-format padd.c 
padd.c:10:11: warning: padding struct 'struct vulnStruct' with 2 bytes to align 'controlledPointer' [-Wpadded]
    char *controlledPointer;
          ^
1 warning generated.

This explains which field was aligned and for what reasons.

Brian Cain
  • 14,403
  • 3
  • 50
  • 88
0

Your controlledPointer needs to start at an address that is a multiple of 8.

struct vulnStruct {
    char start[20];
    char overflow[10]; // 30 bytes
    // 30 is not a multiple of 8.
    // 2 bytes padding here
    // now controlledPointer starts at an address that is a multiple of 8
    char *controlledPointer; 
};
Jts
  • 3,447
  • 1
  • 11
  • 14
  • Most processors permit it to start unaligned, it's just there's a speed penalty for doing so. – Loren Pechtel Mar 13 '16 at 23:03
  • @LorenPechtel Yeah some do, and some crash. In general, a pointer, compiled in 64 bits, 99% of the times, will be 8-byte aligned. Only reason why a compiler should not generate a properly aligned structure is if you tell the compiler to do so because it would be a disaster if you had an array of such unaligned structure, every element in the array, every pointer, would not be aligned. – Jts Mar 13 '16 at 23:55