Mutating member of anonymous struct causes memory permission error

I have a struct called keys with some anonymous structs and unions in it. This is it:

struct keys {
  union {
    struct {
      union {
        struct {
          unsigned char a : 1;
          unsigned char b : 1;
          unsigned char sel : 1;
          unsigned char strt : 1;
        };
        unsigned char keys1 : 4;
      };
      union {
        struct {
          unsigned char u : 1;
          unsigned char d : 1;
          unsigned char l : 1;
          unsigned char r : 1;
        };
        unsigned char keys2 : 4;
      };
    };
    unsigned char c;
  };
} keys;

Changing the value of keys1and keys2, like this keys.keys1 = 0xf; works fine, but things like keys.a = 0; cause a memory permission error.

1 Like

And I thought I was good at coding… what language is this?

Its C++

Ok, and what are structs and unions?

A structure is a group of variables in 1, while a union is 2 or more variables that share a region of memory. So in

union p {
  char a;
  char b;
} q;

q.a and q.b are the same, is my understanding.

This is a good article explaining structs and unions:


@DarkMakesRobots May I ask, what is it that you’re trying to do/accomplish with this code?

1 Like

I’m trying to port some software to V5 that requires the controller keys be put into anonymous structs and unions, but it was originally written in C so there are some problems with porting it.

I had a theory on why this might not be working, so I wrote a minimal version of your code that worked, then I copied your code as-written and it worked. The project in question. You might be doing something else that’s causing this other than what you’ve listed here, or my compiler is fixing some mistake in usage here that VEXcode’s is not.

I tried the same code as John in VEXcode, works ok for me.
But honestly, why bitfields ? They always cause problems, it’s not like you really have to save memory.

code
int main() {
    struct keys {
      union {
        struct {
          union {
            struct {
              unsigned char a : 1;
              unsigned char b : 1;
              unsigned char sel : 1;
              unsigned char strt : 1;
            };
            unsigned char keys1 : 4;
          };
          union {
            struct {
              unsigned char u : 1;
              unsigned char d : 1;
              unsigned char l : 1;
              unsigned char r : 1;
            };
            unsigned char keys2 : 4;
          };
        };
        unsigned char c;
      };
    } keys;
    
    keys.keys1 = 0xf;
    
    printf("%d %d %d\n",keys.a,keys.b,keys.keys1); this_thread::sleep_for(1000);
    
    keys.a = 0;
    
    printf("%d %d %d\n",keys.a,keys.b,keys.keys1); this_thread::sleep_for(1000);
    
    keys.b = 0;
    
    printf("%d %d %d\n",keys.a,keys.b,keys.keys1); this_thread::sleep_for(1000);
}
2 Likes

Bitfields are used because this program that I’m porting (Cinoop) uses bitfields for the keys.

1 Like

When I first read the title, I thought it was a plot for an sci-fi action movie inspired by a comic book: Mutating member of anonymous causes memory error

If I knew what it really was, I may have chosen not to click on it - my brains still hurt from looking at that code. :smile:

I assume it is a not a compilation, but a runtime error. I don’t remember exact details, but I once run into compiler mistakenly evaluating something like keys.a not to an offset 0 inside the outer structure, but to absolute address 0 for the memory reference.

I understand it is a third party project and you don’t want to make a lot of code modifications. But could you try to reduce the number of nesting levels and see what happens:

struct keys {
  union {
    unsigned char c; // byte (8 bits)
    struct {     //  nibbles (4 bits)
        unsigned char keys1 : 4;
        unsigned char keys2 : 4;
    };
    struct { // single addressable bits
        unsigned char a : 1;
        unsigned char b : 1;
        unsigned char sel : 1;
        unsigned char strt : 1;
        unsigned char u : 1;
        unsigned char d : 1;
        unsigned char l : 1;
        unsigned char r : 1;
    };
  };
} keys;
3 Likes

Cinoop :slight_smile:

I will be looking for your github repo of tetris for V5…

1 Like

I once accidentally memcpy’d to 0x00 and it caused the same error, so I’ll try this fix and see if it works.

After changing some things, I figured out that changing a variable inside of the if statement is the problem. The issue is, I need an if statement in order to make this code useful.

if(Controller.ButtonA.pressing() == true) {keys.a = 0;}
that fails and causes an error
keys.a = 0; outside of an if isnt a problem though.

can you post a simple, complete example that demonstrates the problem. There are too many things we don’t know about how you are using this variable, is it global or local, things like that.

Is it even possible for this to be the cause of the problem?
I don’t think it can have anything to do with having it nested in the if statement.
Maybe your controller call is the problem?
Or maybe it actually only crashes when keys.a != 0 (when the button has not been pressed yet)?

hmm I didn’t think about the fact that I wasn’t pressing a button.

The code is here. I determined that it was some problem in the line
if(Controller.ButtonA.pressing() == true) {keys.a = 0;}
because the cout statements dont stop until this line.

Are you supposed to have a delay in the main loop?
Aside from that, I’m guessing the issue is caused by keys not being 0.

ps. If you were to do this project in pros, they have a feature that when the program crashes it outputs the current stack addresses, which you can use to find the exact line that made it crash.
image

1 Like

yea, I can look at that as well in some of my development tools. It seems to crash in the standard library, but I doubt it has anything to do with the keys variable, probably a memcpy or something like that.

putting a delay in the loop just slows down the emulation, and delays the crash, it seems to happen somewhere around 60000 iterations. But that’s about as much as I have time to debug today. It’s something to do with the emulator corrupting memory, but theres too much code to debug quickly. Adding many std::cout (without any loop delays) is also not helping, you are filling the IO buffers too fast and they probably will cause VEXcode some issues.