-1

When defining a variable without initialization on either the stack or the free store it usually has a garbage value, as assigning it to some default value e.g. 0 would just be a waste of time.

Examples:

int foo;//uninitialized foo may contain any value
int* fooptr=new int;//uninitialized *fooptr may contain any value

This however doens't answer the question of where the garbage values come from. The usual explanation to that is that new or malloc or whatever you use to get dynamically allocated memory don't initialize the memory to some value as I've stated above and the garbage values are just leftover from whatever program used the same memory prior.

So I put this explanation to the test:

#include <iostream>

int main()
{
    int* ptr= new int[10]{0};//allocate memory and initialize everything to 0
    for (int i=0;i<10;++i)
    {
        std::cout<<*(ptr+i)<<"   "<<ptr+i<<std::endl;
    }
    delete[]ptr;
    ptr= new int[10];//allocate memory without initialization
    for (int i=0;i<10;++i)
    {
        std::cout<<*(ptr+i)<<"   "<<ptr+i<<std::endl;
    }
    delete[]ptr;
}

Output:

0   0x1291a60
0   0x1291a64
0   0x1291a68
0   0x1291a6c
0   0x1291a70
0   0x1291a74
0   0x1291a78
0   0x1291a7c
0   0x1291a80
0   0x1291a84
19471096   0x1291a60
19464384   0x1291a64
0   0x1291a68
0   0x1291a6c
0   0x1291a70
0   0x1291a74
0   0x1291a78
0   0x1291a7c
0   0x1291a80
0   0x1291a84

In this code sample I allocated memory for 10 ints twice. The first time I do so I initialize every value to 0. I use delete[] on the pointer and proceed to immediately allocate the memory for 10 ints again but this time without initialization.

Yes I know that the results of using an uninitialized variable are undefined, but I want to focus on the garbage values fro now.

The output shows that the first two ints now contain garbage values in the same memory location. If we take the explanation for garbage values into consideration this leaves me only one conclusion: Between deleting the pointer and allocating the memory again something must have tampered with the values in those memory locations.

But isn't the free store reserved for new and delete? What could have tampered those values?

Edit: I removed the std::cout as a comment pointed it out. I use the compiler Eclipse 2022-06 comes with (MinGW GCC) using default flags on Windows 10.

Aiko
  • 183
  • 9
  • 4
    The line `std::cout< – Barmar Aug 16 '22 at 17:12
  • 2
    _Usually_ this is because the user-level memory allocator (the implemntation of `malloc`, `free`, `::operator new`, etc) stores some of its own data in the spaces not currently in use by the application. Without knowing what CPU, OS, compiler, and C and C++ runtimes you used for this test, we cannot be more specific. – zwol Aug 16 '22 at 17:15
  • 1
    If memory you allocate is not initialized, it will contain *indeterminate* values. You should treat all such values as garbage. And what's worse, the C++ specification says that using indeterminate values in any way, even just printing them, leads to *undefined behavior*. – Some programmer dude Aug 16 '22 at 17:15
  • @Someprogrammerdude that's exactly what I wrote in my question... – Aiko Aug 16 '22 at 17:18
  • Incidentally, any "desktop" operating system (as opposed to"embedded"--nowadays the OS on your phone counts as "desktop") *will* erase any data formerly belonging to other *programs* in memory freshly allocated to your program. It would be a security hole not to do this. You can rely on this behavior *if* you use the OS-level allocator (e.g. `mmap`) directly. – zwol Aug 16 '22 at 17:19
  • @Someprogrammerdude Not helpful. OP said they were trying to investigate the actual behavior on their system, which is a legitimate thing to do, even for language-level UB. – zwol Aug 16 '22 at 17:21
  • 2
    If you want to understand your specific behavior, then you really need to go inte much more details. Like operating system, compiler used, version of the compiler, the exact compiler flags used. The behavior of a compiled program depends on many factors, and all could play part of the actual observed behavior. Also note that C and C++ are two ***very*** different languages. What's UB in one language might not be in the other (which could happen with uninitialized integer, using such values *might* lead to UB in C, but it's *always* UB in C++). – Some programmer dude Aug 16 '22 at 17:25
  • 2
    And as hinted by @Barmar, the exact implementation of the standard library and all functions and code you use and call needs to be examined in detail. – Some programmer dude Aug 16 '22 at 17:26
  • You can see if my guess was correct by getting rid of that code that prints the blank lines between the two groups. – Barmar Aug 16 '22 at 17:29
  • 1
    fyi, 12458744 is equal to 0xBE1AF8, just 0x0070 beyond the end of the allocated array, so whatever used the memory at the start of your array was possibly used as a pointer to heap; as others have mentioned, library calls like stream methods could utilize heap. – franji1 Aug 16 '22 at 17:34
  • 1
    If you use the native Windows compiler (MS), it will fill *all* memory with various known patterns in debug mode. Helps finding bugs. [When and why will a compiler initialise memory to 0xCD, 0xDD, etc.](https://stackoverflow.com/questions/370195/when-and-why-will-a-compiler-initialise-memory-to-0xcd-0xdd-etc-on-malloc-fre) – BoP Aug 16 '22 at 17:56
  • Too many people seem to misunderstand the term "garbage value". This is not a thing of itself. There's no way to look at a value alone and say it is or it is not a garbage value. The term describes a value that it is unsafe to rely upon, on account of the language semantics not providing a way to determine what that value should be. Thus, for example, it does not make sense to say that an uninitialized local variable *usually* has a garbage value -- its initial value is *always* unspecified, and reading it produces undefined behavior. – John Bollinger Aug 16 '22 at 18:09
  • I think people should avoid the term "garbage value" in this context, as it encourages a belief, if an `int` (or other variable) is uninitialised, that printing it must produce output without observable patterns (e.g. not zero, not `1234`, not `1111`, etc) whereas *any* output is actually perfectly feasible. *Testing* what garbage is produced is an example of meaningless endeavours following from all that. Being undefined behaviour, it is perfectly feasible that results will vary for no obvious reason, unless one knows specific details of the host or implementation. – Peter Aug 17 '22 at 02:19
  • The answer is quite different between C and C++. In C, the heap is not used by library functions unless you are explicitly told as much by the documentation (`getline` or `strdup` for example). No standard lib functions in C use the heap other than malloc & friends (obviously). In C++, the heap is frequently used by all manner of libraries, including std::string, std::ostream, std::vector and so on. – Lundin Aug 17 '22 at 08:22
  • I can reproduce this on MSVC++ (same CRT as Mingw) and swapping out iostream.h for stdio.h made everything zero. So it's a qualified guess that something in the ostream class uses the heap, simple as that. – Lundin Aug 17 '22 at 08:32
  • @Lundin All C library functions are allowed to use `malloc` for internal scratch space, except the comparatively short list of async-signal-safe functions (and that's only by implication -- malloc is not itself async-signal-safe, therefore no async-signal-safe function can use it) – zwol Aug 18 '22 at 12:50
  • @zwol Well sure, it's not explicitly forbidden to be used. But using it would be unfortunate, since that would render the standard lib useless in many situations, like when using embedded systems. And I can't really think of many (any?) standard lib functions that would actually need to use it. – Lundin Aug 18 '22 at 13:38
  • @Lundin The case that comes readily to mind is formatted I/O; decimal to floating point conversion in particular (both directions) may require more scratch space (for bignums) than can reasonably be put on the stack. – zwol Aug 18 '22 at 16:42

2 Answers2

2

One of the things you need to understand about heap allocations is that there is always a small control block also allocated when you do a new. The values in the control block tend to inform the compiler how much space is being freed when delete is called.

When a block is deleted, the first part of the buffer is often overwritten by a control block. If you look at the two values you see from your program as hex values, you will note they appear to be addresses in the same general memory space. The first looks to be a pointer to the next allocated location, while the second appears to be a pointer to the start of the heap block.

Edit: One of the main reasons to add this kind of control block in a recently deallocated buffer is that is supports memory coalescence. That two int signature will effectively show how much memory can be claimed if that space is reused, and it signals that it is empty by pointing to the start of the frame.

Mikel F
  • 3,567
  • 1
  • 21
  • 33
2

When defining a variable without initialization on either the stack or the free store it usually has a garbage value, as assigning it to some default value e.g. 0 would just be a waste of time.

No. The initial value of a variable that is not initialized is always garbage. All garbage. This is inherent in "not initialized". The language semantics do not specify what the value of the variable is, and reading that value produces undefined behavior. If you do read it and it seems to make sense to you -- it is all zeroes, for example, or it looks like the value that some now-dead variable might have held -- that is meaningless.

This however doens't answer the question of where the garbage values come from.

At the level of the language semantics, that question is non-sensical. "Garbage values" aren't a thing of themselves. The term is descriptive of values on which you cannot safely rely, precisely because the language does not describe where they come from or how they are determined.

The usual explanation to that is that new or malloc or whatever you use to get dynamically allocated memory don't initialize the memory [so the] values are just leftover from whatever program used the same memory prior.

That's an explanation derived from typical C and C++ implementation details. Read again: implementation details. These are what you are asking about, and unless your objective is to learn about writing C and / or C++ compilers or implementations of their standard libraries, it is not a particularly useful area to probe. The specifics vary across implementations and sometimes between versions of the same implementation, and if your programs do anything that exposes them to these details then those programs are wrong.

I know that the results of using an uninitialized variable are undefined, but I want to focus on the garbage values fro now.

No, apparently you do not know that the results of using the value of an uninitialized variable are undefined. If you did, you would not present the results of your program as if they were somehow meaningful.

You also seem not understand the term "garbage value", for in addition to thinking that the results of your program are meaningful, you appear to think that some of the values it outputs are not garbage.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157