I'm new to ACSL and I tried to replicate the function contract of this copy function provided by "ACSL by Example" from the Fraunhofer Society. The Code below works perfectly and every goal gets proven.
/*#
predicate IsValidRange(uint8_t* a, integer n) =
(0 <= n) && \valid(a+(0.. n-1));
*/
/*#
predicate
IsEqual{A,B}(uint8_t* a, integer n, uint8_t* b) =
\forall integer i; 0 <= i < n ==>
\at(a[i], A) == \at(b[i], B);
*/
/*#
requires IsValidRange(a, n);
requires IsValidRange(b, n);
requires \separated(a+(0..n-1), b+(0..n-1));
assigns b[0..n-1];
ensures IsEqual{Here,Here}(a, n, b);
*/
void copy(const uint8_t *a, uint8_t n, uint8_t *b)
{
uint8_t i = 0;
/*#
loop invariant 0 <= i <= n;
loop invariant IsEqual{Here,Here}(a, i, b);
loop assigns b[0..n-1], i;
loop variant n-i;
*/
while (i < n)
{
b[i] = a[i];
++i;
//# assert 0 < i <= n;
}
}
I tried to adjust the specifications to fit my slightly different copy function. This one cannot be proven. Am I missing some important assertions that would assist the automatic prover or is my approach fundamentally flawed?
/*#
requires IsValidRange(src, len);
requires IsValidRange(dst, len);
requires len != 0;
requires \separated(src+(0 .. len-1), dst+(0 .. len-1));
assigns dst[0 .. \old(len)-1];
ensures IsEqual{Here,Here}(src, \old(len), dst);
*/
void Copybytes(
uint8_t const *src,
uint8_t *dst,
uint8_t len
)
{
uint8_t temp;
//# assert 0 != len;
/*#
loop invariant bound: 0 <= len <= \at(len,LoopEntry);
loop invariant equal: IsEqual{Here,Here}(src, \at(len,LoopEntry)-len, dst);
loop assigns dst, src, len, temp;
loop variant len;
*/
do
{
temp = *src;
src++;
*dst = temp;
dst++;
//# assert 0 < len <= \at(len,LoopEntry);
} while (--len != 0u);
}
This is the wp output I get after running the code:
[wp] 17 goals scheduled
[wp] [Alt-Ergo 2.4.0] Goal typed_Copybytes_ensures : Timeout (Qed:11ms) (10s)
[wp] [Alt-Ergo 2.4.0] Goal typed_Copybytes_loop_invariant_equal_prese
rved : Timeout (Qed:9ms) (10s)
[wp] [Alt-Ergo 2.4.0] Goal typed_Copybytes_assigns_part4 : Timeout (Qed:6ms) (10s) (cached)
[wp] [Alt-Ergo 2.4.0] Goal typed_Copybytes_assert_2 : Timeout (Qed:6ms) (10s)
[wp] [Alt-Ergo 2.4.0] Goal typed_Copybytes_loop_assigns_part2 : Timeout (Qed:7ms) (10s)
[wp] [Cache] found:3, updated:6
[wp] Proved goals: 12 / 17
Qed: 8 (1ms-3ms-7ms)
Alt-Ergo 2.4.0: 4 (16ms-31ms) (86) (interrupted: 5) (cached: 3)
Your loop assigns is incorrect: you should mention that the loop body is modifying the content of the dst buffer, not only the pointer itself. Something like loop assigns dst, src, len, temp, dst[0 .. \at(len, Pre)]; should be better.
Note that, in theory, you could restrict the range of changed cells to dst[len .. \at(len,Pre)]. However, in practice, WP can easily get confused when confronted to an assigned block whose length changes from one loop step to the other, so that it is usually better to give the full extent of the range directly (the drawback is that you might have to write another invariant specifying that the elements in dst[0 .. len - 1] haven't changed yet, but as far as I can tell this is not needed here, since we never use the value of these elements anywhere).
Finally, a small tip: assigns-related goal are usually quite easy to prove. If you see that some of them cannot be discharged, checking that you haven't forgotten something there is a good place to start investigating.
Related
I'm a beginner on C and I don't understand all features of this beautiful language yet.
So, I have a very strange problem which doesn't affect my solution at all, I anyway get the right result.
So, the task is:
Given an array of integers.
Return an array, where the first element is the count of positives numbers and the second element is sum of negative numbers. 0 is neither positive nor negative.
If the input is an empty array or is null, return an empty array.
Example:
For input [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15], you should return [10, -65].
My solution:
void count_positives_sum_negatives(
int *values, size_t count, int *positivesCount, int *negativesSum)
{
while(count-- > 0 ? (*values > 0 ? ++*positivesCount : (*negativesSum += *values)) + values++ : 0);
}
'count' contains size of array
But it gives me this "error" or "warning", which strangely doesn't affect my program at all:
solution.c:6:94: warning: unsequenced modification and access to 'values' [-Wunsequenced]
while(count-- > 0 ? (*values > 0 ? ++*positivesCount : (*negativesSum += *values)) + values++ : 0);
~~~~~~ ^
1 warning generated.
How do I fix this?
FIXED:
while(count-- > 0 ? (*values > 0 ? ++*positivesCount : (*negativesSum += *values)) + 1 : 0) values++;
You write (*values...) + values++. There's no sequence point between the operands of +, so reading from (ie: using values in the expression *values) and writing to (ie: updating values in values++) is undefined behavior.
To fix, simply write the code more simply, using multiple statements and expressions rather than try to one-line it.
For example, I might write it like this:
typedef struct stats_s {
int positive_counts;
int64_t negative_sum;
} stats_s ;
stats_s get_stats(const int *xs, size_t count) {
stats_s s = {0, 0};
for (size_t i = 0; i < count; i++) {
if (xs[i] > 0) s.positive_counts++;
else s.negative_sum += xs[i];
}
return s;
}
On your question
"But it gives me this "error" or "warning", which strangely doesn't affect my program at all".
It's a warning. Usually when you get a warning, you have a problem in your code. In this case you have Undefined Behavior (UB on StackOverflow).
For your specific question ("How do I fix this?"), the answer is "don't write such monstrosity". Avoid one liners.
But, probably you want to know where the problem is. The problem is that in this sum
(*values > 0 ? ++*positivesCount : (*negativesSum += *values)) + values++
~~~~~~ ^
you can legally evaluate values++ before or after *values. So, depending on the compiler feeling for this, it can generate different machine code (and behavior) for the same source code. It's usually possible to observe this, by changing the optimization levels or in MSVC switching between Debug and Release mode.
What did you expect? values++ to happen after the first term is evaluated? Then put it in another statement.
On the problem statement
In C language you cannot "return an array". So it's impossible to fulfill the request. Your code lacks all the checks required by the problem statement. You also didn't reset the accumulator variables.
If we assume that "return an array" = "return an allocated piece of memory able to contain two numbers or NULL to indicate an empty array" (which is totally arbitrary), this could be a solution:
int *count_positives_sum_negatives(int *values, size_t count)
{
if (values == NULL || count == 0) {
return NULL;
}
int *ret = calloc(2 * sizeof(int));
for (size_t i = 0; i < count; ++i) {
if (values[i] > 0) {
ret[0] += 1;
}
else {
ret[1] += values[i];
}
}
return ret;
}
I found the solution, just move values++ to the body of the loop:
#include <stddef.h>
void count_positives_sum_negatives(
int *values, size_t count, int *positivesCount, int *negativesSum)
{
while(count-- > 0 ? (*values > 0 ? ++*positivesCount : (*negativesSum += *values)) + 1 : 0) values++;
}
So no more undefined behaviour.
The example in this question seems to work only for fixed-length arrays, however the similar code below from https://frama-c.com/html/acsl.html doesn't seem to pass. As soon as I change the code to be include the requirement && n == 42 (or any other positive integer) it passes.
When it fails it says [wp] [Alt-Ergo 2.4.1] Goal typed_set_to_0_loop_invariant_established : Timeout (Qed:1ms) (1') (cached)
/*#
requires \valid(a+(0..n-1));
assigns a[0..n-1];
ensures
\forall integer i;
0 <= i < n ==> a[i] == 0;
*/
void set_to_0(int* a, int n){
int i;
/*#
loop invariant 0 <= i <= n;
loop invariant
\forall integer j;
0 <= j < i ==> a[j] == 0;
loop assigns i, a[0..n-1];
loop variant n-i;
*/
for(i = 0; i < n; ++i)
a[i] = 0;
}
Any tips on how to proceed / what the intended behaviour/flags are?
Actually, the loop invariant 0 <= i <= n is not true if n is strictly negative. A loop invariant must hold the first time you reach the loop (this is what the "established" part means, as opposed to the "preserved" part in which you must check that it holds at the end of any loop step, assuming it was true at the beginning of said step), even if you don't end up entering the loop at all (which is obviously the case here if n<0). You must thus add a requires n >=0; in the contract of the function.
EDIT
I forgot to mention that another solution is of course to make n and i unsigned (or even better to #include <stddef.h> and use size_t): this way, you are guaranteed a positive number without having to write an additional requires)
In my example below, frama-c isn't able to prove my assign clause in the function contract and I am not sure why. I would really appreciate any help.
/*#
# requires n>0;
# requires \valid(a+(0..n-1));
# ensures \forall int i; (n>i>=0 ==> a[i]==0);
#*/
void f(int n, float *a) {
/*#
# loop invariant n>=0;
# loop invariant test: \forall int j; (n>j>i ==> a[j]==0);
# loop assigns i, a[0..n-1];
#*/
for (int i=n-1; i>=0; i--) {
a[i] = 0;
}
}
Here is my ouput:
[wp] 8 goals scheduled
[wp] [Alt-Ergo] Goal typed_f_loop_assign_part3 : Unknown (Qed:24ms) (406ms)
[wp] Proved goals: 7 / 8
Qed: 5 (4ms-13ms-24ms)
Alt-Ergo: 2 (20ms-32ms) (28) (unknown: 1)
I'm just zeroing out an array in reverse order in this program.
You are missing a loop invariant on i. As a result, WP has no idea of the range of values it can take, and cannot prove that the indexes of a that are being written are 0 .. n-1. Just add
# loop invariant -1 <= i <= n-1;
(Notice that at the end of the last iteration, i is -1, not 0.)
Shake sort of vector:
program works, but:
I was trying to use the same function for bubble up and bubble down for shake sort (bubble up to get the MAX value to the right and bubble down to get the min value to the left). In order to do it I was trying to use the following MACRO which does not compile:
sign is '+' and oper is '>' for bubble
sign is '-' and oper is '<' for bubble down
for bubble up -
start is iterator i (iterated the Vector indices)
end is n-1-i;
for bubble down -
swap start and end values
#define bubble_up_down(var_t, pVector, _Is_swp, start, end, sign, oper)\
{\
var_t current_index;\
var_t current_val;\
var_t next_val;\
for (current_index = *(start) ; current_index (oper) *(end) ; (sign)(sign)current_index){\
{\
VectorGet((pVector), current_index, ¤t_val);\
VectorGet((pVector), current_index(sign)1, &next_val);\
if(current_val (oper) next_val)\
{\
VectorSet((pVector), current_index, next_val);\
VectorSet((pVector), current_index(sign)1, current_val);\
*(_Is_swp) = 1;\
}\
}\
}
Need your advice to fix this macro.
It is not really clear why you want to use a macro here. Do you want to avoid duplicaing code? Or do you want to make your sorting routine type independent?
Anyway, your macro has several errors:
You've probably read that you should guard macro arguments with parentheses. That is usually good advice, because macros are text replacements; for example infamous SQ(x + 1) will resolve to x + 1*x + 1. In your case, the advice is wrong-headed. You will get syntactically wrong "operators" such as (-) and (<) in your code. Just use sign and oper.
Even so, sign sign will resolve to - - or + +, which is not what you want. You could rewrite i++ to the equally valid i = i + 1 or you could use the token-pasting operator, sign##sign, which would produce -- or ++.
Macros aren't functions. You are probably going to invoke your macro inside a function. All local variables that are in scope hen you invoke the macro are also in scope for the macro. That means there is probably no need to define all these pointers.
Why do you pass the array element type, var_t? I reckon that SetVector and GetVector aren't macros, so the type independence falls flat.
If var_t is the type of your array elements, your index isn't necessarily of the same type; it should be an integer type. (Your elements must be comparable with the < operator, so it is one of the arithmetic types, but image what happens if you have an array of char that is longer than 256 elements?)
If your elements are of arithmetic type, there's probably no need for the GetValue and SetValue calls. You can just assign values with the = operator .
All this makes me think that you don't really know what you're doing. That plus the known pitfalls and shortcomings of macros are a good reason not to use any macros here.
Addendum In comments, The PO has said that the macro should achieve two things: It should avoid repeated code and it should make the sorting independent of the types of the array elements. These are two different things.
Writing short local macros to avoid repeating code can be a useful technique, especially, if the code needs to keep variables in sync in several places. Is it useful in your situation?
So you've got your upward-bubbling code:
int done = 0;
while (!done) {
done = 1;
for (int i = 1; i < n; i++) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
}
(This uses a swap function to swap two array elements. It is more straightforward than your version, because it doesn't use get/set accessor functions.) Now you write the downward-bubbling counterpart:
while (!done) {
done = 1;
for (int i = n - 1; i > 0; i--) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
}
These two snippets differ only in the loop control. Both visit all indices from 1 to n - 1. So your macro needs to pass the start and end values. But it also needs to know which way the comparison goes – less than or greater than – and whether to increment or to decrement the index. That's four pieces of data for a simple loop.
You could try to get rid of the comparison and use != for both directions. But then your loops will fail if the array is empty.
The above backwards loop will already fail on empty arrays when you use an unsigned integer as index. Forward and backward lops are asymmetric an C, because the lower and upper bounds are asymmetric, too: Lower bound are always inclusive, upper bound are always exclusive. This forward loop:
for (unsigned int i = 0; i < n; i++) ...
Has the following backward equivalent:
for (unsigned int i = n; i-- > 0; ) ...
Here, the decrement occurs in the condition and the update part is empty. The advantage is that it uses exactly the same bounds, 0 and n, verbatim, but by decrementing before entering the loop body, the same valid range of numbers, 0 to n - 1 are visited. And it works with unsigned ints, which are a natural choice for looping variables.
To cut a long story short: Forward and backward loops are asymmetric in C, so it is not easy to write a macro for them. C's for syntax is more verbose than for i = 1 to n, but that's how it is. Embrace it and alleviate the typing pain by chosing appropriate index names: it's i, not current_index.
Can you make the code less redundant without macros? Of course: You can write two functions for bubbling up and down once:
static int bubble_up(int a[], int n)
{
int done = 1;
for (int i = 1; i < n; i++) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
return done;
}
static int bubble_down(int a[], int n)
{
int done = 1;
for (int i = n; i-- > 1; ) {
if (a[i - 1] > a[i]) {
swap(a, i - 1, i);
done = 0;
}
}
return done;
}
(These functions are static, i.e. private to the current compilation unit.) Now your actual sorting functions look like this:
void sort_bubble_up(int a[], int n)
{
int done = 0;
while (!done) {
done = bubble_down(a, n);
}
}
void sort_bubble_down(int a[], int n)
{
int done = 0;
while (!done) {
done = bubble_down(a, n);
}
}
void sort_shaker(int a[], int n)
{
int done = 0;
while (!done) {
done = bubble_up(a, n) || bubble_down(a, n);
}
}
If you are not afraid of empty loop bodies, you can even get them down to:
void sort_bubble_up(int a[], int n)
{
while (bubble_down(a, n)) { }
}
void sort_bubble_down(int a[], int n)
{
while (bubble_down(a, n)) { }
}
void sort_shaker(int a[], int n)
{
while (bubble_up(a, n) || bubble_down(a, n)) { }
}
All this code works only for int arrays, though. The standard library's way of approaching type independence is to work on the byte level via void * pointers and user-defined comparison functions. The sorting function qsort does this, for example.
C++ and other languages have templates, where you can write an algorithm for several types. When you "instantiate" a template, the compiler creates a function for just this type, which is then called.
You could emulate this with macros. If you just want to call your macro in the function body, you could define:
#define BUBBLE_SORT(ARRAY, N, TYPE) do { \
int done = 0; \
int i; \
\
while (!done) { \
done = 1; \
\
for (i = 1; i < N; i++) { \
if (ARRAY[i - 1] > ARRAY[i]) { \
TYPE sawp = ARRAY[i]; \
\
ARRAY[i] = ARRAY[i - 1]; \
ARRAY[i - 1] = swap; \
done = 0; \
} \
} \
} \
} while (0)
and then use the macro like so:
char c[] = "Mississippi";
BUBBLE_SORT(c, strlen(c), char);
(That do { ... } while (0) thing around thze macro makes the macro behave like a function call, sort of. The new scope of the loop body allows for local variables.)
The problem here is that such multi-line macros are hard to debug. When there is an error in the body, you just get the number of the line where the macro is invoked in an error message. (But you can use -E with most compilers to see how the preprocessor resolves that macro.)
Conclusion:
Macros can be useful, but you have to know what you are doing. In general, try to avoid them, because they are hard to debug and often hard to understand for others. (And this other person might be you half a year later.)
If you must use macros, try to make then look as natural as possible. Passing operators like > or + should make you wary.
Use functions, not macros, for common code.
Embrace C's way to deal with different types. It will be more useful (if less fun) to learn how qsort works than to fiddle with macros for a bubble sort implementation.
If you really need to write a lot of type-independent code, you probably shouldn't use C.
This question already has answers here:
Faster approach to checking for an all-zero buffer in C?
(19 answers)
Closed 7 years ago.
I have a mass of data, maybe 4MB. Now want to check if all bits in it are 0.
Eg:
Here is the data:
void* data = malloc(4*1024*1024);
memset(data, 0, 4*1024*1024);
Check if all bits in it are 0. Here is my solution which is not fast enough:
int dataisnull(char* data, int length)
{
int i = 0;
while(i<length){
if (data[i]) return 0;
i++;
}
return 1;
}
This code might have some things to improve in performance. For example, in 32/64 bits machine, checking 4/8 bytes at a time may be faster.
So I wonder what is the fastest way to do it?
You can handle multiple bytes at a time and unroll the loop:
int dataisnull(const void *data, size_t length) {
/* assuming data was returned by malloc, thus is properly aligned */
size_t i = 0, n = length / sizeof(size_t);
const size_t *pw = data;
const unsigned char *pb = data;
size_t val;
#define UNROLL_FACTOR 8
#if UNROLL_FACTOR == 8
size_t n1 = n - n % UNROLL_FACTOR;
for (; i < n1; i += UNROLL_FACTOR) {
val = pw[i + 0] | pw[i + 1] | pw[i + 2] | pw[i + 3] |
pw[i + 4] | pw[i + 5] | pw[i + 6] | pw[i + 7];
if (val)
return 0;
}
#endif
val = 0;
for (; i < n; i++) {
val |= pw[i];
}
for (i = n * sizeof(size_t); i < length; i++) {
val |= pb[i];
}
return val == 0;
}
Depending on your specific problem, it might be more efficient to detect non zero values early or late:
If the all zero case is the most common, you should compute cumulate all bits into the val accumulator and test only at the end.
If the all zero case is rare, you should check for non zero values more often.
The unrolled version above is a compromise that tests for non zero values every 64 or 128 bytes depending on the size of size_t.
Depending on your compiler and processor, you might get better performance by unrolling less or more. You could also use intrinsic functions available for your particular architecture to take advantage of vector types, but it would be less portable.
Note that the code does not verify proper alignment for the data pointer:
it cannot be done portably.
it assumes the data was allocated via malloc or similar, hence properly aligned for any type.
As always, benchmark different solutions to see if it makes a real difference. This function might not be a bottleneck at all, writing a complex function to optimize a rare case is counterproductive, it makes the code less readable, more likely to contain bugs and much less maintainable. For example, the assumption on data alignment may not hold if you change memory allocation scheme or if you use static arrays, the function may invoke undefined behavior then.
The following checks if the first byte is what you want, and all subsequent pairs of bytes are the same.
int check_bytes(const char * const data, size_t length, const char val)
{
if(length == 0) return 1;
if(*data != val) return 0;
return memcmp(data, data+1, length-1) ? 0 : 1;
}
int check_bytes64(const char * const data, size_t length, const char val)
{
const char * const aligned64_start = (char *)((((uintptr_t)data) + 63) / 64 * 64);
const char * const aligned64_end = (char *)((((uintptr_t)data) + length) / 64 * 64);
const size_t start_length = aligned64_start - data;
const size_t aligned64_length = aligned64_end - aligned64_start;
const size_t end_length = length - start_length - aligned64_length;
if (!check_bytes(data, start_length, val)) return 0;
if (!check_bytes(aligned64_end, end_length, val)) return 0;
return memcmp(aligned64_start, aligned64_start + 64, aligned64_length-64) ? 0 : 1;
}
A more elaborate version of this function should probably pass cache-line-aligned pointers to memcmp, and manually check the remaining blocks(s) instead of just the first byte.
Of course, you will have to profile on your specific hardware to see if there is any speed benefit of this method vs others.
If anyone doubts whether this works, ideone.
I once wrote the following function for my own use. It assumes that the data to check is a multiple of a constant chunk size and aligned properly for a buffer of machine words. If this is not given in your case, it is not hard to loop for the first and last few bytes individually and only check the bulk with the optimized function. (Strictly speaking, it is undefined behavior even if the array is properly aligned but the data has been written by any type that is incompatible with unsigned long. However, I believe that you can get pretty far with this careful breaking of the rules here.)
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
bool
is_all_zero_bulk(const void *const p, const size_t n)
{
typedef unsigned long word_type;
const size_t word_size = sizeof(word_type);
const size_t chunksize = 8;
assert(n % (chunksize * word_size) == 0);
assert((((uintptr_t) p) & 0x0f) == 0);
const word_type *const frst = (word_type *) p;
const word_type *const last = frst + n / word_size;
for (const word_type * iter = frst; iter != last; iter += chunksize)
{
word_type acc = 0;
// Trust the compiler to unroll this loop at its own discretion.
for (size_t j = 0; j < chunksize; ++j)
acc |= iter[j];
if (acc != 0)
return false;
}
return true;
}
The function itself is not very smart. The main ideas are:
Use large unsigned machine words for data comparison.
Enable loop unrolling by factoring out an inner loop with a constant iteration count.
Reduce the number of branches by ORing the words into an accumulator and only comparing it every few iterations against zero.
This should also make it easy for the compiler to generate vectorized code using SIMD instructions which you really want for code like this.
Additional non-standard tweaks would be to annotate the function with __attribute__ ((hot)) and use __builtin_expect(acc != 0, false). Of course, the most important thing is to turn on your compiler's optimizations.