2

I created a structure like that:

struct Options {
    double bindableKeys = 567;
    double graphicLocation = 150;
    double textures = 300;
};
Options options;

Right after this declaration, in another process, I open the process which contains the structure and search for a byte array with the struct's doubles but nothing gets found.

To obtain a result, I need to add something like std::cout << options.bindableKeys;after the declaration. Then I get a result from my pattern search. Why is this behaving like that? Is there any fix?

Minimal reproducible example:

struct Options {
    double bindableKeys = 567;
    double graphicLocation = 150;
    double textures = 300;
};
Options options;
while(true)  {
    double val = options.bindableKeys;
    if(val > 10)
        std::cout << "test" << std::endl;
}

You can search the array with CheatEngine or another pattern finder

heromato
  • 75
  • 5
  • 4
    Compiler probably optimizes it away if you do not use it. – Hawky Dec 23 '19 at 13:16
  • I use it consistently a few lines later. – heromato Dec 23 '19 at 13:19
  • If it isn’t use, it won’t be linked. Even when it is linked it will need a sufficiently substantial use that the compiler can’t see through it and optimize it away. – Dietmar Kühl Dec 23 '19 at 13:20
  • @heromato Then it is probably created on the first use, not when you "create it" in your code. – Hawky Dec 23 '19 at 13:21
  • Not able to imagine what you are trying to say. Plz elaborate – Build Succeeded Dec 23 '19 at 13:24
  • Most likely the compiler optimises out the `options` variable if It is not used anywhere in the code. Note that the compiler is very good at following usage down the call tree and simply using a variable in code that is never called (directly or indirectly) usually results in both being optimised away. – Hristo Iliev Dec 23 '19 at 13:27
  • Maybe the structure is optimized out. `if(val > 10)` could be optimized out if `options.bindableKeys` is never touched in any other part of the code. – drescherjm Dec 23 '19 at 13:28
  • Got it, any way forcing the compiler to think it's used more often, or at least something that doesn't print anything to the console? – heromato Dec 23 '19 at 13:30
  • @heromato Yes, I linked to several approaches in my answer. – Lightness Races in Orbit Dec 23 '19 at 13:30
  • Yes, it does not get edited anywhere except from the remote program. – heromato Dec 23 '19 at 13:31

1 Answers1

7

Contrary to popular belief, C++ source code is not a sequence of instructions provided to the executing computer. It is not a list of things that the executable will contain.

It is merely a description of a program.

Your compiler is responsible for creating an executable program, that follows the same semantics and logical narrative as you've described in your source code.

Creating an Options instance is all well and good, but if creating it does not do anything (has no side effects) and you never use any of its data, then it may as well not exist, and therefore is not a part of the logical narrative of your program.

Consequently, there is no reason for the compiler to put it into the executable program. So, it doesn't.

Some people call this "optimisation". That the instance is "optimised away". I prefer to call it common sense: the instance was never truly a part of your program.

And even if you do use the data in the instance, it may be possible for an executable program to be created that more directly uses that data. In your case, nothing changes the default values of Option's members, so there is no reason to include them into the program: the if statement can just have 567 baked into it. Then, since it's baked in, the whole condition becomes the constant expression 567 > 10 which must always be true; you'll likely find that the resulting executable program consequently contains no branching logic at all. It just starts up, then outputs "test" over and over again until you force-terminate it.

That all being said, because we live in a world governed by physical laws, and because compilers are imperfect, there is always going to be some slight leakage of this abstraction. For this reason, you can trick the compiler into thinking that the instance is "used" in a way that requires its presence to be represented more formally in the executable, even if this isn't necessary to implement the described program. This is common in benchmarking code.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055