C program using inotify help in understanding code - c

I was referring the man page for inotify and I came across this piece of code
if (event->mask & IN_ISDIR)
printf(" [directory]\n");
else
printf(" [file]\n");
where event is a pointer to struct inotify_event.
I couldn't understand this particular line if (event->mask & IN_ISDIR) and why a bitwise AND is used here.
How was it determined that the bitwise AND is supposed to be used here and nothing else? It was not mentioned in the man page for inotify.

This bitwise AND is masking out a specific bit (IN_ISDIR). It is testing whether or not this one bit is set or not. If this bit is set in event->mask, it evaluates to true.
For example,
#include <stdio.h>
#define FIRST_BIT 1
#define SECOND_BIT 2
#define THIRD_BIT 4
int main() {
int x = 3; /* 3 in binary is 011 */
if ( x & FIRST_BIT )
printf("First bit is set\n");
if ( x & SECOND_BIT )
printf("Second bit is set\n");
if ( x & THIRD_BIT )
printf("Third bit is set\n");
}
will give the output
First bit is set
Second bit is set
From inotify.h:
#define IN_ISDIR 0x40000000 /* event occurred against dir */
This value has only one bit set. (In binary, this is 01000000000000000000000000000000.) A bitwise AND with this (0x40000000) and some variable will evaluate to either 0 (if the variable has a 0 here), or 0x40000000 if the variable has a 1 in the same place. Any non-zero value is considered "true".
Logically, it is testing if the event was from a directory (instead of a file).

A bitwise AND is just an easy (and very common) way to check if a specific bit is set.
The man page is clear that if that bit is set then the event is referring to a directory.

Related

How does the bitwise AND help in the if statements in the Linux Kernel?

Background on what the code is trying to achieve:
"Various parameters of the new process (e.g., euid, egid, argument list, environment, filename, etc.) that
are subsequently passed to other functions are, for the sake of simplicity, combined into a structure of
type linux_binprm. prepare_binprm is used to supply a number of parent process values (above all, the
effective UID and GID); the remaining data — the argument list — are then copied manually into the
structure. Note that prepare_binprm also takes care of handling the SUID and SGID bits:"
fs/exec.c
int prepare_binprm(struct linux_binprm *bprm)
{
...
bprm->e_uid = current->euid;
bprm->e_gid = current->egid;
if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
/* Set-uid? */
if (mode & S_ISUID) {
bprm->e_uid = inode->i_uid;
}
/* Set-gid? */
/*
* If setgid is set but no group execute bit then this
* is a candidate for mandatory locking, not a setgid
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
bprm->e_gid = inode->i_gid;
}
}
...
}
Here, the bitwise AND (&) is being used in the if-statement to analyze the flags. But what does this achieve? As in, what is the condition its checking and how is it evaluated?
Source: Linux Kernel Architecture
The result of bitwise and expression a & b is a number with value 1 at every bit that is set in both a and b, and value 0 at all other bits. If that result is exactly equal to b (for example) then it must be the case that every bit that is set in b is also set in a. If the result is unequal to b then there must be at least one bit set in b that is not set in a.
In your particular example, mode is a file mode bitmask, S_ISGID is a macro representing the set-group-id bit of such a mask, and S_IXGRP is a macro representing the group-executable bit of such a mask. The condition then evaluates whether both the S_ISGID bit and the S_IXGRP bit are set in mode. If a regular file has a mode for which that is the case then that file is a setgid executable.

C memory address - what is wrong with the code?

Someone asked me recently to see what is wrong in the following code and how should I fix it:
// Memory-mapped peripheral
#define STATUS_REG_ADDR 0x12345678 // 32-bit status register
#define DATA_REG_ADDR 0x1234567C // 32-bit data register
// Status register bits
#define BUSY_BIT_MASK 0x00000080 // Busy bit == '1' while peripheral busy
uint32_t get_value()
{
while (((*(uint32_t*)STATUS_REG_ADDR) & BUSY_BIT_MASK) == 1)
;
return *(uint32_t*)DATA_REG_ADDR;
}
I never did something similar before, so I tried to run it in an IDE and I saw that the return statement gives a segmentation fault, but I don't know how to explain it and if there something more wrong.
Problem is in while loop condition.
Your BUSY_BIT_MASK is 0x00000080. Anything ANDed with 0x80 will not be equal to 1 as it's LSB is 0. Anything ANDed with 0 is always 0.
You have to modify the condtion as
while (((*(uint32_t*)STATUS_REG_ADDR) & BUSY_BIT_MASK) == BUSY_BIT_MASK)
So that when the flag is set, it will be ANDed with 0x80 and output will be 0x80. (1 AND 1 = 1)
You are getting SegFault because the addresses you are considering are not valid on your computer. You have to take valid addresses. You are trying to access random memory or memory address which may not exist - that is reason for SegFault.

The meaning of a single & in an if statement

Came across a weird notation today while reading through some C code
Can anyone explain to me what the line do?
if ((dwEvent & EV_RXCHAR) && cs.cbInQue) { /* do stuff */}
if ((dwEvent & EV_RXCHAR) && cs.cbInQue) { /* do stuff */}
& is Binary And Operator. & is applied to every bit of both the variables .It checks ,
if result of dwEvent & EV_RXCHAR is non-zero then cs.cbInQue is checked if it is non-zero or not .
If both the conditions are true code in if block is executed .
if result of dwEvent & EV_RXCHAR is zero then without checking cs.cbInQue , code in else block is executed if present.
It masks (performs binary AND operation) dwEvent with EV_RXCHAR, checks if the result is non-zero, checks if cs.cbInQue is non-zero, if both are true, executes code in conditional statement.
This is not necessarily a "weird" notation. Many programmers use it as a shortcut instead of specifying (x & y) != 0.
It is a bitwise operation. You can read it here. link
Its short form to check if the any of the bits EV_RXCHAR are set by checking getting out those bits first (dwEvent & EV_RXCHAR). Then if any of these are set it
would also check if cs.cbInQue is also set then do the stuff.
eg:
unsigned int x = dwEvent & EV_RXCHAR;
if (x !=0)
if (cs.cbInQue != 0)
{ /* do stuff */}

Using a bitmask and if statement

I am trying to allow multiple cases to run in a switch statement. I have a bitmask as follows:
#define SHOOT_ROCKET 2 << 16
#define MOVE_FORWARD 3 << 16
Later, I do
switch (int game_action)
and I have
case SHOOT_ROCKET:
result = fire_weapon(rl);
I don't want to 'break', because I want possibility of multiple actions. But I am returning a value called 'result'. I store this as a variable and return at the end. I can tell other case: statements are running though even when they shouldn't because result keeps getting changed and doesn't if I add break;
What is the best way to deal with this?
Update: I've been told to do if instead.
I changed my << bitmasks so they start at 1 now.
I am experiencing a weird bug
if (game_action->action & SHOOT_ROCKET)
{
game_action->data=5;
}
if (game_action->action & MOVE_FORWARD)
{
game_action->data=64;
}
I am not concerned about game_action being overwritten when I intend for multiple if's to evaluate to true
However: it seems MOVE_FORWARD is happening even if I only try and shoot a rocket!
game_action is a void pointer normally, so this is how it's setup in the function:
game_action = (game_action) *game_action_ptr;
I have verified the bitmask is correct with
printf("%d", game_action->action >> 16) which prints 2.
So why is '3' (the move forward) happening when I am only trying to shoot a rocket?
Please do update your question.
So why is '3' (the move forward) happening when I am only trying to shoot a rocket?
The first thing you want to look at is
#define SHOOT_ROCKET 2 << 16
#define MOVE_FORWARD 3 << 16
and think what that evaluates to. It will evaluate to the following binary numbers (Python is handy for this kind of stuff, 0b is just a prefix that means binary is following):
>>> bin(2 << 16)
'0b100000000000000000'
>>> bin(3 << 16)
'0b110000000000000000'
So you see that you use one bit twice in your #defines (Retired Ninja already pointed this out). This means that if game_action->action is set to anything where the bit 2 << 16 is 1, both of your ifs will evaluate to true, because both #defines have that bit set to 1.
to make them mutually exclusive, should i do 2, 4, 8, instead of 1,2,3,4?
If you want to easily keep track of which bits are used, you can either use powers of two (1,2,4,8,16, etc), e.g. #define MOVE_FORWARD 4 (I'm ignoring the << 16 you have, you can add that if you want), or you can shift a 1 by a variable number of bits, both result in the same binary numbers:
#define MOVE_LEFT 1 << 0
#define MOVE_RIGHT 1 << 1
#define MOVE_UP 1 << 3
#define MOVE_DOWN 1 << 4
There are legitimate cases where bitmasks need to have more than one bit set, for example for checking if any one of several bits are set:
#define MOVE_LEFT ... (as above)
#define SHOOT_ROCKET 1 << 5
#define SHOOT_GUN 1 << 6
//...
#define ANY_MOVEMENT 0xF
#define ANY_WEAPON_USE 0xF << 4
and then check:
if (action & ANY_MOVEMENT) { ... }
if (action & ANY_WEAPON_USE) { ... }
place parens '(' ')' around the value part (2<<15) kind of values so there is no errors introduced by the text replacement.
I.E. this:
'if( (&game_action->action & MOVE_FORWARD) == MOVE_FORWARD)'
becomes
'if( (&game_action->action & 2 << 16) == 2 << 16)'
Note the posted code is missing a left paren, which I added.
Where the '&' has a higher Precedence the '<<' so it (effectively) becomes
'if( ( (&game_action->action & 2) << 16) == 2 << 16)'
where the '&' is done to the 2 and not to the 2<<16

Why is this line obfuscated?

In this snippet,
if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
{
/* statements */
}
the member OscillatorType could have any of the values, or their combination, defined below.
#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000)
#define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001)
#define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002)
#define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004)
#define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008)
Why is the if written this way? Why not simply like this?
if(RCC_OscInitStruct->OscillatorType == RCC_OSCILLATORTYPE_HSI)
RCC_OscInitStruct->OscillatorType is a collection of bits packed in an integer value, each bit representing one of the values (RCC_OSCILLATORTYPE_HSE, ...). That's why they come in powers of 2. The code you showed just checks if the bit associated with RCC_OSCILLATORTYPE_HSI is set. It's very probable that bits of other values are also set.
For example if the binary representation of OscillatorType is 0...011, the first and second bit is set, meaning that the RCC_OSCILLATORTYPE_HSE and RCC_OSCILLATORTYPE_HSI values are selected.
It's a very common C idiom and not obfuscated in any way. Those are two very different tests.
if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
says "if the RCC_OSCILLATOR_HSI bit is 1". It doesn't care whether any of the other bits are 0 or 1, whereas
if (RCC_OscInitStruct->OscillatorType == RCC_OSCILLATORTYPE_HSI)
says "if the RCC_OSCILLATOR_HSI bit is 1 AND all the other bits are 0".
Because it may have any of these values at the same time. The & (bitwise AND) operator is serving the purpose of extracting only the value RCC_OSCILLATOR_TYPE_HSI.
As an example, your input may look like this:
010011
While RCC_OSCILLATOR_TYPE_HSI looks like this:
000010
The AND operator with these two values will return 000010, witch exactly equals RCC_OSCILLATOR_TYPE_HSI.
However, if your input looks like this:
110101
The bitwise AND operator between this and RCC_OSCILLATOR_TYPE_HSI will return 0, and the condition will be false.
The if condition is interested only in the second last bit of RCC_OscInitStruct->OscillatorType. So RCC_OSCILLATORTYPE_HSI is used as a mask and then compared to itself.
If you see all the constants, first one is all zeroes where as the others have its set bit at successive positions.
Now, doing & with any of these constants can tell you whether its corresponding bit is set in the said parameter.
If you want to set all of the possible values, you would be doing:
RCC_OscInitStruct->OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_LSI;
Why comparison using ==?
That's not required and makes the code cluttered. I think that the programmer wanted to bring uniformity when testing for RCC_OSCILLATORTYPE_NONE.
The programmer can't test for RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_NONE because that would evaluate to zero. You are either forced to negate the condition just for this check.
An example:
#include <stdio.h>
#include <stdint.h>
#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000)
#define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001)
#define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002)
#define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004)
#define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008)
int main(void)
{
/* set HSI and HSE */
uint32_t flags = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI;
if (flags == RCC_OSCILLATORTYPE_HSI) {
puts("flags = HSI");
}
if ((flags & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI) {
puts("HSI is set in flags");
}
return 0;
}
Output:
HSI is set in flags
To begin with, == is not equivalent with &. Because == looks at the whole 32 bit register, including any crap you aren't interested in. While & just looks at the relevant parts.
And the & is simple binary arithmetic for bitwise AND. In my opinion, you need to understand binary numbers before even enrolling your first programmer course, but maybe that's just me.
Anyway, given that you actually understand what bitwise AND does, it would have made more sense if you had code like
#define RCC_OSCILLATORTYPE ((uint32_t)0x0000000F) // mask
#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000)
#define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001)
#define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002)
#define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004)
#define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008)
...
(RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE) == RCC_OSCILLATORTYPE_HSI
Maybe this is what the programmer of that code intended, but they didn't quite manage to bring the code all the way there.

Resources