0

For example in this code:

#include <stdio.h>

int main()
{
  char i = 0;
  char j = 0;
  char *p = &i;
  void *q = p;
  int *pp = q;
  printf("%d %d\n", i, j);
  *pp = -1;
  printf("%d %d\n", i, j);

  return 0;
}

if I compile with gcc version 8.1.0 x64 (Ubuntu 8.1.0-5ubuntu1~16.04) the output is:
0 0
-1 -1
now, I use a cast to int *

#include <stdio.h>

int main()
{
  char i = 0;
  char j = 0;
  char *p = &i;
  void *q = p;
  int *pp = (int *)q;
  printf("%d %d\n", i, j);
  *pp = -1;
  printf("%d %d\n", i, j);

  return 0;
}

the result is the same as the previous.
With clang-6.0 x64 the output is:
0 0
-1 0
Is the code apparently a buffer overflow?
I hope I've explained that clearly.

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
theriver
  • 325
  • 2
  • 9
  • There is no difference between the 2 codes, and yes, you are writing outside of `i`. The result of this print then depends on how `i` and `j` are stored in memory. Either way though, it's a bad idea. – Qubit Sep 27 '18 at 10:28
  • The `void *` is not related to your problem as it did not change the result. Also adding the cast did not change anything. How is your question related to the casting of a `void*`? What does clang product for your first code? – Gerhardh Sep 27 '18 at 10:30
  • I would assume tht gcc and clang produce different layout of your variabltes on the stack and depending on that your (illegal) assignment to `*pp` hits `j` or not. – Gerhardh Sep 27 '18 at 10:30

2 Answers2

3

You actually have two problems:

The first is that you break strict aliasing and have undefined behavior.

The second problem is that on most modern platforms the size of an int is four bytes, and the pointer pp is pointing only to a single byte. The assignment you make to *pp will therefore write out of bounds and also lead to undefined behavior.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

Cast or no cast, you are essentially try to use incompatible types, leading to violating strict aliasing rules.

According to C11, chapter §6.5,

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88)

— a type compatible with the effective type of the object,

— a qualified version of a type compatible with the effective type of the object,

— a type that is the signed or unsigned type corresponding to the effective type of the object,

— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,

— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or

— a character type.

But, you try to access the memory allocated for a char via an int type. This violates strict aliasing.

That said, the standard guarantees that size of a char is 1 byte, size of an int is >= char. So, the access would be out of bound and lead to undefined behavior.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261