2

When we defined dynamic array in C/C++ it's using head segment to keep track of number of elements in the array(in heap). for example :

int* mem = new int[8];

compiler will allocate sizeof(int)*8 bytes.

int *temp = malloc(sizeof(int)*9)

Will store "8" in the first sizeof(int) bytes and it goes like this

*temp = 8;

and then set mem address with next consecutive address respect to temp

mem = temp + 1;

Therefore,mem will points to an array of 8 elements, not 9.

And when deletion happens compiler will use mem in reverse process respect to above to deallocate memory in that heap block

delete[] mem;

My question is
If we allocate a dynamic memory which will be used in different modules in run-time and we managed to retrieve number of elements using head segment of allocated heap memory,Is it safe to use in Multi-threaded environment?

(Please assume that in each module by program design,no helper function or attribute provided to retrieve number of elements(size) in defined dynamic array.Each module only passing address(pointers) to array but not its size)

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • 2
    You're assuming a lot of implementation details here. I don't really understand the question, anyway. What is your goal? What are you trying to do? – Lightness Races in Orbit Jan 09 '17 at 15:42
  • Whatever you put in a malloc'd area is safe until it gets deallocated. Beware anyway that an int occupies 4 bytes. –  Jan 09 '17 at 15:42
  • Why do you want to do that? What is the reasoning behind it? What is the real problem that you want to solve? – Werner Henze Jan 09 '17 at 15:43
  • @YvesDaoust: It may not. – Lightness Races in Orbit Jan 09 '17 at 15:49
  • 1
    @YvesDaoust, who told you that `int` occupies 4 bytes? – SergeyA Jan 09 '17 at 15:49
  • 1
    @YvesDaoust, well, my recent `int`s are occupying 2 bytes. What your 30 years of coding have to say to it? – SergeyA Jan 09 '17 at 15:53
  • 1
    @YvesDaoust: [You'll need a few more years then!](http://stackoverflow.com/a/11438840/560648) Don't forget to read as well as code. – Lightness Races in Orbit Jan 09 '17 at 15:54
  • 1
    @YvesDaoust: Then you already know that what you are claiming is not true. – Lightness Races in Orbit Jan 09 '17 at 15:55
  • Your question is still unclear. Accessing arrays in a multithreaded environment is safe in the sense that it will not crash, but you may end up reading partially updated (i.e. corrupted) data if some other thread updated the array. – Sven Nilsson Jan 09 '17 at 15:56
  • 1
    @LightnessRacesinOrbit: int has been 32 bits for the last 20 years and will remain so in the future. –  Jan 09 '17 at 15:56
  • 1
    @YvesDaoust, I can only repeat myself - as recently as yesterday I was working with modern hardware with 16 bit int. – SergeyA Jan 09 '17 at 15:57
  • 2
    @YvesDaoust: `int` is still 16 bits on most architectures and can have 1-2 bytes easily! You might have to extend your horizon; 32 or 64 systems are still the minority. – too honest for this site Jan 09 '17 at 16:03
  • 1
    @olaf: back in 1992, the 64 bits DEC Alpha was a dream processor ! I also enjoyed (years before) the IBM 360 storing FORTRAN BOOLEANS in 72 bits words. –  Jan 09 '17 at 16:10

4 Answers4

3

No, it is not safe in any environment. You can't rely on the compiler storing the number of elements in the array before the allocated memory, as it is not defined behavior. You should never try to get to this value.

Instead, do not even use dynamic arrays, but opt for std::vector.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • To be fair, Buddhika did say "**if** we managed to retrieve number of elements" – Lightness Races in Orbit Jan 09 '17 at 15:43
  • @LightnessRacesinOrbit, yes indeed. I will try to make the point clearer. – SergeyA Jan 09 '17 at 15:44
  • I don't think that the OP uses addresses "before". He uses the first byte to store the size. –  Jan 09 '17 at 15:44
  • @YvesDaoust, I believe, OP is trying to get to the value used by compiler internally. – SergeyA Jan 09 '17 at 15:45
  • @SergeyA: you didn't look at the code. `*temp= 8` clearly stores the length in the first position. –  Jan 09 '17 at 15:46
  • ,Thank for the reply all of you such quick time!! –  Jan 09 '17 at 15:46
  • regardless it's still UB because of `realloc` (which may use the same location). Unless the OP can guarantee that the pointer will not be modified in either module it creates a potential data race. That still ignores the fact that it's UB from a standards perspective as the standard doesn't require such an implementation and the implementation is free do do other things to track allocations. – Mgetz Jan 09 '17 at 15:47
  • @Mgetz: no, realloc won't cause any trouble (provided care is taken to restore the initial value of the pointer, like will be done before a free). –  Jan 09 '17 at 15:48
  • @YvesDaoust, I believel, OP is illustrating the point by arguing about compiler behavior. – SergeyA Jan 09 '17 at 15:49
  • @YvesDaoust it will in a multi-threaded environment if the size of the array is modified but the location is not. It breaks the rules requiring a data-race free program. – Mgetz Jan 09 '17 at 15:50
  • @SergeyA,instead of std::vector,most of game engine dev' companies use some magic tricks to keep track of number of elements rather than rely on std::containers,some of them use sometimes functions like _alloca and _malloca within a function boundaries to alloc mem on stack based on some allocated mem ,for that they need size to define i. Please refer -> https://msdn.microsoft.com/en-us/library/5471dc8s.aspx –  Jan 09 '17 at 15:50
  • @Buddhika, I see no reason to use `alloca` when in C++ VLAs are supported as extension in any sensible compiler. On any rate, no-allocation approach is very different from your original question. – SergeyA Jan 09 '17 at 15:51
  • @SergeyA I just go through this article http://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard Yeah I will try another approach,but if you find any theoretical or compiler dependent or independent logic please reply. –  Jan 09 '17 at 15:55
  • Quite a few games used to allocate a massive block of memory and then use their own memory manager to hand it out as required. This should give you as much control as you need without infringing on the runtime or the OS. – user4581301 Jan 09 '17 at 15:56
  • @Mgetz: the system will take care that the block header remains consistent with the block and the heap state. So, no, no trouble (of course reading the size and accessing the block must be made atomically). –  Jan 09 '17 at 15:57
  • And while I'm not a fan of VLA, VLA seems much safer to me than having stack-based storage you can forget to return. – user4581301 Jan 09 '17 at 15:58
  • @Buddhika just use the [GSL](https://github.com/Microsoft/gsl) it has range constructs, and they are very lightweight. – Mgetz Jan 09 '17 at 16:04
  • @Mgetz thank you very much for the tip!! it's really helpful!! – Buddhika Chaturanga Jan 09 '17 at 16:19
1

Accessing mem - 1 has undefined behaviour.

compiler will ...

If you target that version of compiler, and that version only, and the compiler vendor documents the behaviour, then perhaps you can trust that the version of the compiler indeed does as you have observed.

But a program that depends on it will be non-portable to other compilers, and possibly other versions of that same compiler, and possibly to other platforms that use same version of the same compiler.

This is all regardless of multi vs single thread.


If we allocate a dynamic memory which will be used in different modules in run-time and we managed to retrieve number of elements using head segment of allocated heap memory,Is it safe to use in Multi-threaded environment?

It is safe to use dynamic memory in a multi threaded program as much as it is safe to use any memory. Of course, multi threaded implies the potential for data races. You must synchronize modifications to any objects that may simultaneously be accessed by other threads. Whether the objects are in dynamic memory makes no difference.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

I tested this with Visual Studio release build:

int * mem = new int[8];

results in a call to malloc equivalent to

int * mem = malloc(32);    // 32 = 8 * sizeof(int)

The size of the integer array is not stored anywhere, (including the malloc header as far as I can tell, the malloc header just has some type of link/flag used to recombine blocks allocated (and virtually mapped) from the heap).

rcgldr
  • 27,407
  • 3
  • 36
  • 61
0

Using undocumented system information is in principle out of question, even if it seems to work: it might behave differently in unexpected circumstances and there is no guarantee of portability, even across the same manufacturer over time.

If you want to play with matches anyway, make sure that no other thread performs a memory-allocation-related operation between the moment you read the size and the moment you access the block; you need to implement a critical section for this purpose.

  • An extra warning: You can protect your code with whatever you like, but you won't have much luck blocking the runtime from tinkering if it feels the need. – user4581301 Jan 09 '17 at 16:13
  • @user4581301: yep. I guess that the only guarantee that the system can provide is that the content of the block pointed to by the malloc pointer doesn't change between calls, which are thread-safe. –  Jan 09 '17 at 17:37