Specific reasons to use |= instead of = - c

I am currently looking over some code in the Linux kernel (thermal management). In some places there is a return value used to signal errors, which is set to 0 at the beginning of the function. Then when calling a function which may fail it is set to the new value using |= instead of =. Here is an example:
int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
int *temperature)
{
u32 temp;
int ret;
ret = ti_bandgap_validate(bgp, id);
if (ret)
return ret;
spin_lock(&bgp->lock);
temp = ti_bandgap_read_temp(bgp, id);
spin_unlock(&bgp->lock);
ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
if (ret)
return -EIO;
*temperature = temp;
return 0;
}
The definition of ti_bandgap_validate is:
/**
* ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
* #bgp: struct ti_bandgap pointer
* #id: bandgap sensor id
*
* Checks if the bandgap pointer is valid and if the sensor id is also
* applicable.
*
* Return: 0 if no errors, -EINVAL for invalid #bgp pointer or -ERANGE if
* #id cannot index #bgp sensors.
*/
static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
So, if my reasoning is correct, at the call to ti_bandgap_adc_to_mcelsius(), the value of ret must be 0 (otherwise the function would have exited already). So what is the reason for using |= here instead of =? Doing an "or" with a pattern of all zeros will just give back the normal pattern. Is this some kind of optimization for the usual case, i.e. that the function is returning no failure (i.e. return value 0)? Or is there some other difference I am missing? This code is running on an ARM-architecture, so it might have to do something with specific optimizations for that platform.

In this case, there is no reason to use |= however, if you are tracking a number of functions that might error, and return if they error as the return code, the pattern is
boolean error = false
error |= doFirstStep(...);
error |= doSecondStep(...);
error |= doThirdStep(...);
if (error) {
printf("error occurred: %s\n", strerror(errno));
}
It is a lesser used pattern in C, occasionally used in languages with some affinity with C. In the C language, a great number of C library functions return an "error code" which is typically 0 on successful operation.
When using this pattern, the user relies on the return of zero as a success condition. This means that the above-mentioned log_and_recover() might pull the error message out of the error.h a static variable, as is common to the C #include <error.h> routines.
---- To continue in why this is often used on int fields ----
You also see this pattern with an int holding the error.
int error = 0; // or a variable that's defined to zero
error |= doFirstStep(...);
error |= doSecondStep(...);
error |= doThirdStep(...);
if (error != 0) {
... some error handling ...
}
When you see this, it is the same idea as above, but the developer combined two patterns. The bit field pattern which is often used for packing configuration parameters is being leveraged to pack multiple kinds of errors. Typically when this happens you can find a list of errors similar to
#define ERROR_NO_DISK (1<<1);
#define ERROR_NO_NETWORK (1<<2);
#define ERROR_NO_SANITY (1<<3);
It isn't terribly sensible for most items to return multiple errors and handle them as one; but sometimes it is done when error suppression is important. For example, if you fail transmit a message from a client to a host, odds are you could suppress the various "failure to open a socket", "failure to write to socket", "failure to copy to buffer", etc. failures into a generic "failure to send X". At one level, the entire top level workflow failed, and if needed the details of why are still somewhat available.

There's no reason to use |= in this context. As you stated, ret must be 0 when this line is reached, otherwise it would have returned earlier. It also introduces an additional operation which is unnecessary.
As was mentioned in the comments, this operator was in fact changed to = in this commit. The commit comment states:
Avoid confusing |= on error values.

Related

How to properly utilize masks to send index information to perf event output?

According to the documentation for bpf_perf_event_output found here: http://man7.org/linux/man-pages/man7/bpf-helpers.7.html
"The flags are used to indicate the index in map for which the value must be put, masked with BPF_F_INDEX_MASK."
In the following code:
SEC("xdp_sniffer")
int xdp_sniffer_prog(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
if (data < data_end) {
/* If we have reached here, that means this
* is a useful packet for us. Pass on-the-wire
* size and our cookie via metadata.
*/
/* If we have reached here, that means this
* is a useful packet for us. Pass on-the-wire
* size and our cookie via metadata.
*/
__u64 flags = BPF_F_INDEX_MASK;
__u16 sample_size;
int ret;
struct S metadata;
metadata.cookie = 0xdead;
metadata.pkt_len = (__u16)(data_end - data);
/* To minimize writes to disk, only
* pass necessary information to userspace;
* that is just the header info.
*/
sample_size = min(metadata.pkt_len, SAMPLE_SIZE);
flags |= (__u64)sample_size << 32;
ret = bpf_perf_event_output(ctx, &my_map, flags,
&metadata, sizeof(metadata));
if (ret)
bpf_printk("perf_event_output failed: %d\n", ret);
}
return XDP_PASS;
}
It works as you would expect and stores the information for the given CPU number.
However, suppose I want all packets to be sent to index 1.
I swap
__u64 flags = BPF_F_INDEX_MASK;
for
__u64 flags = 0x1ULL;
The code compiles correctly and throws no errors, however no packets get saved at all anymore. What am I doing wrong if I want all of the packets to be sent to index 1?
Partial answer: I see no reason why the packets would not be sent to the perf buffer, but I suspect the error is on the user space code (not provided). It could be that you do not “open” the perf event for all CPUs when trying to read from the buffer. Have a look at the man page for perf_event_open(2): check that the combination of values for pid and cpu allows you to read data written for CPU 1.
As a side note, this:
__u64 flags = BPF_F_INDEX_MASK;
is misleading. The mask should be used to mask the index, not to set its value. BPF_F_CURRENT_CPU should be used instead, the former only happens to work because the two enum attributes have the same value.

Why does thread not recognize change of a flag?

I have a strange situation under C/Visual Studio on a Windows 7 platform. There is a problem from time to time and I spent a lot of time to find it. The problem is within a third party library, for which I have the complete code. There a thread is created (the printLog statements are from myself):
...
plafParams->eventThreadFlag = 2;
printLog("before CreateThread");
if (plafParams->hReadThread_p = CreateThread(NULL, 0, ( LPTHREAD_START_ROUTINE ) plafPortReadThread, ( void * ) dlmsInstance, 0,
&plafParams->portReadThreadID) )
{
printLog("after CreateThread: OK");
plafParams->eventThreadFlag = 3;
}
else
{
unsigned int lasterr = GetLastError();
printLog("error CreateThread, last error:%x", lasterr);
/* Could not create the read thread. */
...
...
return FAILURE;
}
printLog("SUCCESS");
...
...
The thread function is:
void *plafPortReadThread(DLMS_GLOBALS *dlmsInstance)
{
PLAF_PARAMS *plafParams;
plafParams = (PLAF_PARAMS *)(dlmsInstance->plafParams);
printLog("start - plafPortReadThread, plafParams->eventThreadFlag=%x", plafParams->eventThreadFlag);
while ((plafParams->eventThreadFlag != 1) && (plafParams->eventThreadFlag != 3))
{
if (plafParams->eventThreadFlag == 0)
{
printLog("exit 1 - plafPortReadThread, plafParams->eventThreadFlag=%x", plafParams->eventThreadFlag);
CloseHandle(plafParams->hReadThread_p);
plafFree((void **)&plafParams);
ExitThread(0);
break;
}
}
printLog("start - plafPortReadThread, proceed=%d", proceed);
...
Now, when the flag is set before the while loop is started within the thread, everything works OK:
SUCCESS
start - plafPortReadThread, plafParams->eventThreadFlag=3
But sometimes the thread is quick enough so the while loop is started before the flag is actually set within the outer part.
The output is then:
start - plafPortReadThread, plafParams->eventThreadFlag=2
SUCCESS
Most surprisingly the while loop doesn't exit, even after the flag has been set to 3.
It seems, that the compiler "optimizes" the flag and assumes, that it cannot be changed from outside.
What could be the problem? I'm really surprised. Or is there something else I have overseen completely? I know, that the code is not very elegant and that such things should better be done with semaphores or signals. But it is not my code and I want to change as little as possible.
After removing the whole while condition it works as expected.
Should I change the struct or its fields to volatile ? Everybody says, that volatile is useless in our days and not needed anymore, except in the case, where a memory location is changed by peripherals...
Prior to C11 this is totally platform-dependent, because the effect you are observing is due to the memory model used by your platform. This is different from a compiler optimization as synchronization points between threads require the compiler to insert barrier instructions, instead of, e.g., making something a constant. For C11 for section 7.17.3 specifies the different models. So your value is not optimized out statically, thread A just never reads the value thread B wrote, but still has its local value.
In practice many projects don't use C11 yet, and thus you will likely have to check the documentation of your platform. Note that in many cases you don't have to modify the type of the variable for the flag (in case you can't). Most memory models specify synchronization points that also forbid reordering of certain instructions, i.e. in:
int x = 3;
_Atomic int a = 1;
x = 5;
a = 2;
the compiler will often have to ensure that x has the value 3 when a has the value 1, and that when a is assigned the value 2, x will have the value 5. volatile does not participate in this relationship (in the C/C++ 11 models - often confused because it does participate in Java's happened-before), and is mostly useless, unless your writes should never be optimized out because they have side-effects such as a LED blinking which the compiler can't understand:
volatile int x = 1; // some special location - blink then clear
x = 1; // blink then clear
x = 1; // blink then clear

Probably a pointer issue but not sure why

This is going to be a bit abstract due to the specific ARM (LPCXpresso 1115R/303) Cortex M0 and the H6 bluetooth module, and with NXP software there are a ton of driver files that are linked so hopefully the code snip below will be enough to identify the problem.
I am creating a simple menu system through bluetooth. Everything works with communcation. I send the message from the board, it is visible on the phone, I respond and print the value in the console of the program. All are exactly what I want them to be. But this is what happens:
1) start debug session and resume
2) 1st menu sends to phone, correct.
3) Type response to phone and send, correct.
4) message appears in console exactly as entered from phone (Just the number 1 appears)
5) Have if loop that checks to see if Buffer value == '1';
6) must not == 1 because it never enters the loop.
7) reprints the value of the buffer, and it still equals 1.
The only hint I have is a warning that says "makes integer from pointer without a cast [-Wint-conversion]" on the assignment line as indicated below.
void ArmPeripheral() {
UARTCount = 0;
LPC_UART->IER = IER_THRE | IER_RLS; /* Disable RBR */
UARTSend( (uint8_t *)menu1, sizeof(menu1));
LPC_UART->IER = IER_THRE | IER_RLS | IER_RBR; /* Re-enable RBR */
while(1) {
if(UARTCount != 0){
printf("%s 1st print\n",UARTBuffer);
int bVal = UARTBuffer; // This is where the error occurs, tried uint8_t, did not work.
printf("%s This is bVal\n",bVal);
if(bVal == 1) { //have tried 1, '1', and "1" none work
printf("inside loop %s...\n",UARTBuffer);
printf("%s This is bVal\n",bVal);
LEDControl();
}
printf("%s second print\n",UARTBuffer);
UARTCount = 0;
}
}
}
enter image description here
Nevermind, it was just a simple pointer issue. UARTBuffer is a external volatile uint8_t in the UART.c file, and even though it is not defined as a pointer, it is pointing to a buffer somehow.
int bVal = *UARTBuffer;
if(bVal == '1') {
The above worked, but if anyone has any more in depth information that could explain why I would be interested in knowing. This is how I initialized the buffer:
extern volatile uint32_t UARTCount;
extern volatile uint8_t UARTBuffer[BUFSIZE];

Setting the x86 debug registers during handling of an exception

I am able to set up a HW breakpoint (writing or reading of an address) without problems and it also works.
If I try to do the same from a Vectored Exception handler the registers are set (confirmed it with set/getThreadContext), but the same SW never breaks.
The address and the setup functions are the same, the only difference that I see is that, if I set the breakpoint from the main code, it works; if I do the same from a vectored exception handler (during where an unrelated exception has happened) the breakpoint will not have any effect.
The code that should break on the breakpoint is of course outside of the exception handler.
I can't find any relevant information in the IA32 Software Manual.
Perhaps some of you had this problem. Any help is appreciated.
Edit:
Here is a very crude example, don't mind the warnings. If compiled with #define DIRECT, the program terminates because of the uncaught SINGLE_STEP, if compiled without nothing happens.
To be clear, this is just an ugly, messy, quick example.
// The following macros define the minimum required platform. The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified.
// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER // Specifies that the minimum required platform is Windows Vista.
#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98.
#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
#endif
#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0.
#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE.
#endif
#include "windows.h"
#include "stdio.h"
#define DR7_CONFIG(num, lg, rw, size) ((((rw & 3) << (16 + 4 * num)) | ((size & 3) << (18 + 4 * num))) | (lg << (2 * num)))
HANDLE mainThread;
//#define DIRECT
DWORD WINAPI LibAsilEmu_ArrayBoundsMonitor(LPVOID lpParameter)
{
MSG msg;
CONTEXT tcontext;
HANDLE th;
DWORD temp = 0;
IMAGE_SECTION_HEADER *psec;
th = OpenThread(THREAD_ALL_ACCESS, FALSE, mainThread);
temp = SuspendThread(th);
tcontext.ContextFlags = CONTEXT_DEBUG_REGISTERS;
temp = GetThreadContext(th, &tcontext);
tcontext.Dr6 = 0;
tcontext.Dr0 = lpParameter;
tcontext.Dr2 = lpParameter;
tcontext.Dr3 = lpParameter;
tcontext.Dr1 = lpParameter;
tcontext.Dr7 = 0xffffffff;//DR7_CONFIG(0, 1, 2, 3) | DR7_CONFIG(1, 1, 2, 3) | 256;
temp = SetThreadContext(th, &tcontext);
temp = GetThreadContext(th, &tcontext);
temp = ResumeThread(th);
return 0;
}
HANDLE child;
unsigned int test_array[10];
LONG WINAPI LibAsilEmu_TopLevelVectoredFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
child = CreateThread(NULL, 0x4000, LibAsilEmu_ArrayBoundsMonitor, &test_array[2], 0, NULL);
while (WAIT_OBJECT_0 != WaitForSingleObject(child, 0));
return EXCEPTION_CONTINUE_EXECUTION;
}
int main(void)
{
int i;
printf("%p\n", test_array); fflush(stdout);
printf("sizeof %d\n", sizeof(test_array));
mainThread = GetCurrentThreadId();
#ifdef DIRECT
child = CreateThread(NULL, 0x4000, LibAsilEmu_ArrayBoundsMonitor, &test_array[2], 0, NULL);
// Edit 2: the wait was missing
while (WAIT_OBJECT_0 != WaitForSingleObject(child, 0));
#else
AddVectoredExceptionHandler(1, &LibAsilEmu_TopLevelVectoredFilter);
RaiseException(0,0,0,0);
#endif
printf("thread ready\n");
printf("ta %p\n", &(test_array[10]));
for (i = 0; i < 15; ++i)
{
*((char*)test_array) += 0x25;
test_array[i] += 0x15151515;
printf("%2d %d %p\n", i, test_array[i], &(test_array[i])); fflush(stdout);
}
printf("ta %d\n", test_array[10]);
printf("exit\n\nexit\n\n");
return 0;
}
I do not know the specifics of your problem because there is no code provided in your description. i.e., it could simply be a coding error. So, with no other information all that I can think is to point you to a link with some example code on using vectored exception handling HERE Hope this helps, otherwise, post some code
[EDIT 1]
First, I would guess you are not the first to see this problem, Vectored exception handling has been around since XP. Others most certainly have seen it.
Probably no need to say it (but I will anyway) debuggers, when running multiple threads behave differently than they do in
in single thread. You are calling your vectored exception handler from a separate thread. It seems likely this is somehow related to the fact you cannot see the breakpoint when running from thread. Do you have the abilty to point your debugger to a specific thread? See Here
I have one other suggestion - Since the real point of this question is to determine why your HW break point is not being set when attempted using a Vectored Exception Handler, consider changing the title of this post to something like:
Cannot set HW breakpoints using Vectored Exception handler.
it may get more attention. (I would have done this myself, but did not want to make the presumption you would be okay with that :)
[EDIT 2]
I see in your example that in main(), you are calling AddVectoredExceptionHandler() from within a new thread. But the function
LONG WINAPI LibAsilEmu_TopLevelVectoredFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
child = CreateThread(NULL, 0x4000, LibAsilEmu_ArrayBoundsMonitor, &test_array[2], 0, NULL);
while (WAIT_OBJECT_0 != WaitForSingleObject(child, 0));
return EXCEPTION_CONTINUE_EXECUTION;
}
creates yet another new thread, where LibAsilEmu_ArrayBoundsMonitor in turn opens the main thread again. This seems an odd series of events to me. Is this code something you have seen used somewhere else, and used in conjunction with vectored exception handling?

Error when dealing with memory - mremap_chunk: Assertion

It seems like my previous post but issue here is different ..
This is the C structure for problem -
typedef struct ip_esp_private { /* keep track of things privately */
u_int32_t type;
u_int32_t ivlen;
u_int32_t icvlen;
u_int32_t keylen; /* length of "Encryption key */
u_int32_t akeylen; /*length of authn key */
u_int32_t key[0]; /* encryption key and authentication key both */
} esp_private;
The values are provided to structure contents at run time as follows -
case 'k': /* Key */
length = stringargument(arg, &temp);
priv->keylen = length;
priv = (esp_private *)realloc(priv,
sizeof(esp_private)+/*length*/priv->keylen);
/*This one is edited */
// if(priv->akeylen)
// memmove(&priv->key[priv->keylen],
// &priv->key[0],priv->akeylen);
/*These three are commented*/
memcpy(&priv->key[0], temp, priv->keylen);
pack->private = priv;
pack->modified |= ESP_MOD_KEY;
break;
case 'K': /* Authentication Key */
length = stringargument(arg, &temp);
priv->akeylen = length; // marked line(explained below)
priv = (esp_private *)realloc(priv,
sizeof(esp_private)+/*length*/priv->keylen+priv->akeylen);
/*this one edited too */
memcpy(&priv->key[priv->keylen/sizeof(u_int32_t)],
temp,priv->akeylen);
pack->private = priv;
pack->modified |= ESP_MOD_KEY;
Now there is a function which uses the value of authentication key.
The relevant part of the function is -
if (!epriv->akeylen) {
key = &fakekey;
keylen = 1;
} else {
key = (u_int8_t *)malloc(epriv->akeylen);
memcpy(key,&epriv->key[epriv->keylen/sizeof(u_int32_t)]
,epriv->akeylen);
Now when I tried to run the following program , getting this error about which I have no idea.
sendip: malloc.c:3574: mremap_chunk: Assertion `((size + offset)
& (mp_.pagesize-1)) == 0' failed.
I think may be there is a error in function part but what exactly it is I am not sure,
because when I comment the marked line (mentioned above) the akeylen is null
so taking that fakekey value and program runs fine.
Edit 1:
I have edited the code at three places (also edited in the above code ).
Now program works but an inconsistent output occurs.
Input :
Encryption key - qwerty
Authentication key - abcdef
Output:
Encryption key - qwerab
Authentication key - abcdef
The situation is more clear now .
The problem it means is surely there at realloc statements .
Please suggest on this.
Initially I added length at both realloc statements but now I changed it to priv->keylen at first place and priv->keylen+priv->akeylen at secone place.
But something still needs to be improved
Why this is overwriting ???
Since the key[0] struct hack appears to contain space for both keys, you'll need to allocate memory for both, too. In both cases ('k' and 'K' )
priv = realloc(priv, sizeof *priv +priv->keylen+priv->akeylen);
When concatenating the two keys, it is easiest to cast the u_int32_t key into a character pointer and do arithmatic on that one:
memcpy ( priv->key, source1, sizeofsource1);
/* and */
memcpy ( ((char*) priv->key) +priv->keylen, source2, sizeofsource2);
[and similar for the memmove()]
The rest of the casts in your program can be removed.
If you get assertion failures from within malloc, the problem is outside. The assertion is not about the parameters passed to malloc, but about the state of the memory, which is corrupted. This means that you previously wrote to a memory area you were not supposed to write. So even if you provided a proper traceback (using gdb for instance), this would not point you to the source of the problem. There are a number of tools for debugging memory problems. One of the most widely used tools is valgrind. It will make your program horribly slow and show you tons of possible problems by looking at every single memory access. Another more lightweight tool is mudflap, which is to be linked against. A very basic approach to narrowing down the problem is to add assert(condition) statements to your code and hope that you fail earlier. Sometimes you can solve this problem by looking at every single memory access in your code and ensure that it is not out of bounds (or if you are unsure, add an assertion statement).

Resources