* Observe wrapping variables in while loops
@ 2009-03-08 4:22 Roel Kluin
2009-03-09 16:20 ` Steven Rostedt
0 siblings, 1 reply; 3+ messages in thread
From: Roel Kluin @ 2009-03-08 4:22 UTC (permalink / raw)
To: Steven Rostedt; +Cc: lkml
Inspired by your definition of 'if', I came up with something to test variable
wrapping in while loops, and was wondering if this was useful for the linux
kernel:
The source below is adapted to illustrate how it works. If you run it, this
will print:
8 6 4 2 0 variable wraps at ../test.c:88:main(): -1!
...-2
9 7 5 3 1 variable wraps at ../test.c:94:main(): -1!
...-1
8 7 6 5 4 3 2 1 0 ...-1
8 7 6 5 4 3 2 1 ...0
21 22 23 24 25 26 27 28 29 30 ...31
19 18 17 16 15 14 13 12 11 10 ...9
4 3 2 1 0 -1 -2 -3 -4 -5 ...-6
-5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 ...11
4 2 0 variable wraps at ../test.c:129:main(): -1!
...-2
In the first two loops and the last, a wrap occurs due to the double decrement.
Tests like 'while(i++ < 30)' and 'while(j-- > -5)' are boolean.
However, this may not work for a construction like this:
while ((ret = foo())) {
do_stuff();
}
------------------------------>8-------------8<---------------------------------
#include <stdio.h>
struct while_data {
const char *func;
const char *file;
unsigned line;
unsigned long last;
};
int is_while_wrap(struct while_data *w, unsigned long val)
{
if (w->last < val) {
printf("variable wraps at %s:%u:%s(): %d!\n", w->file, w->line, w->func, val);
return 0;
}
w->last = val;
return val;
}
#define __while_check__(x) ({ \
static struct while_data \
______w = { \
.func = __func__, \
.file = __FILE__, \
.line = __LINE__, \
.last = ULONG_MAX, \
}; \
printf(" "); \
is_while_wrap(&______w, (x)); \
})
#define while(x) while(__while_check__(x))
int main(int argc, char* argv[])
{
unsigned int i=9;
while(i--) {
printf("%d", i);
--i;
}
printf("...%d\n", i);
i=10;
while(--i) {
printf("%d", i);
--i;
}
printf("...%d\n", i);
i=9;
while(i--)
printf("%d", i);
printf("...%d\n", i);
i=9;
while(--i)
printf("%d", i);
printf("...%d\n", i);
i=20;
while(i++ < 30)
printf("%d", i);
printf("...%d\n", i);
i=20;
while(i-- > 10)
printf("%d", i);
printf("...%d\n", i);
int j=5;
while(j-- > -5)
printf("%d", j);
printf("...%d\n", j);
while(j++ < 10)
printf("%d", j);
printf("...%d\n", j);
j=5;
while(j--) {
printf("%d", j);
j--;
}
printf("...%d\n", j);
}
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: Observe wrapping variables in while loops 2009-03-08 4:22 Observe wrapping variables in while loops Roel Kluin @ 2009-03-09 16:20 ` Steven Rostedt 2009-03-11 19:16 ` Roel Kluin 0 siblings, 1 reply; 3+ messages in thread From: Steven Rostedt @ 2009-03-09 16:20 UTC (permalink / raw) To: Roel Kluin; +Cc: lkml On Sun, 8 Mar 2009, Roel Kluin wrote: > Inspired by your definition of 'if', I came up with something to test variable > wrapping in while loops, and was wondering if this was useful for the linux > kernel: > > The source below is adapted to illustrate how it works. If you run it, this > will print: > > 8 6 4 2 0 variable wraps at ../test.c:88:main(): -1! > ...-2 > 9 7 5 3 1 variable wraps at ../test.c:94:main(): -1! > ...-1 > 8 7 6 5 4 3 2 1 0 ...-1 > 8 7 6 5 4 3 2 1 ...0 > 21 22 23 24 25 26 27 28 29 30 ...31 > 19 18 17 16 15 14 13 12 11 10 ...9 > 4 3 2 1 0 -1 -2 -3 -4 -5 ...-6 > -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 ...11 > 4 2 0 variable wraps at ../test.c:129:main(): -1! > ...-2 > > In the first two loops and the last, a wrap occurs due to the double decrement. > Tests like 'while(i++ < 30)' and 'while(j-- > -5)' are boolean. > > However, this may not work for a construction like this: Interesting variation. Now the question is, how many bugs are we aware of that were caused by wraps? If there are a few, then I would say this is definitely something to look at. Otherwise, it may not be worth putting this in mainline. -- Steve > > while ((ret = foo())) { > do_stuff(); > } > ------------------------------>8-------------8<--------------------------------- > #include <stdio.h> > > struct while_data { > const char *func; > const char *file; > unsigned line; > unsigned long last; > }; > > int is_while_wrap(struct while_data *w, unsigned long val) > { > if (w->last < val) { > printf("variable wraps at %s:%u:%s(): %d!\n", w->file, w->line, w->func, val); > return 0; > } > w->last = val; > return val; > } > > #define __while_check__(x) ({ \ > static struct while_data \ > ______w = { \ > .func = __func__, \ > .file = __FILE__, \ > .line = __LINE__, \ > .last = ULONG_MAX, \ > }; \ > printf(" "); \ > is_while_wrap(&______w, (x)); \ > }) > > #define while(x) while(__while_check__(x)) > > > int main(int argc, char* argv[]) > { > unsigned int i=9; > while(i--) { > printf("%d", i); > --i; > } > printf("...%d\n", i); > i=10; > while(--i) { > printf("%d", i); > --i; > } > printf("...%d\n", i); > > i=9; > while(i--) > printf("%d", i); > printf("...%d\n", i); > > i=9; > while(--i) > printf("%d", i); > printf("...%d\n", i); > > i=20; > while(i++ < 30) > printf("%d", i); > printf("...%d\n", i); > > i=20; > while(i-- > 10) > printf("%d", i); > printf("...%d\n", i); > > int j=5; > while(j-- > -5) > printf("%d", j); > printf("...%d\n", j); > while(j++ < 10) > printf("%d", j); > printf("...%d\n", j); > > j=5; > while(j--) { > printf("%d", j); > j--; > } > printf("...%d\n", j); > } > ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Observe wrapping variables in while loops 2009-03-09 16:20 ` Steven Rostedt @ 2009-03-11 19:16 ` Roel Kluin 0 siblings, 0 replies; 3+ messages in thread From: Roel Kluin @ 2009-03-11 19:16 UTC (permalink / raw) To: Steven Rostedt; +Cc: lkml, Andrew Morton Steven Rostedt wrote: > > > On Sun, 8 Mar 2009, Roel Kluin wrote: > >> Inspired by your definition of 'if', I came up with something to test variable >> wrapping in while loops, and was wondering if this was useful for the linux >> kernel: > Interesting variation. Now the question is, how many bugs are we aware of > that were caused by wraps? If there are a few, then I would say this is > definitely something to look at. Otherwise, it may not be worth putting > this in mainline. > > -- Steve Hi Steve, Andrew, Below is a extended version, that does some more tests. it obviously isn't finished, it requires more work done, but I think it may eventually provide very interesting runtime debugging observations. Roel ------------------------------>8-------------8<--------------------------------- /* (C) Roel Kluin, 2009 GPL v.2 */ #include <stdio.h> #include <string.h> #define ULONG_MAX (~0UL) typedef enum {false, true} bool; #define NULL ((void *)0) struct while_data { const char *func; const char *file; const char *str; unsigned line; bool signd; bool postfix; bool incr; unsigned long last; bool printed; struct while_data *next; }; static struct while_data *while_data_head; int while_unsigned(struct while_data *w, int val) { if (!(w->printed & 1)) { w->next = while_data_head; while_data_head = w; w->signd = false; const char* decrstr = strstr(w->str, "--"); if (decrstr != NULL) { if (strcmp(decrstr, "--") == 0) { w->incr = false; w->postfix = true; } else if (strcmp(decrstr, w->str) == 0) { /* FIXME: we have to ensure that the first part is a variable name and nothing else */ w->incr = false; w->postfix = false; } else { printf("decrement not recognized.\n"); } } else printf("no decrement found.\n"); w->printed |= 1; } if (w->last < val && !(w->printed & 2)) { printf("variable wraps at %s:%u:%s()!\n", w->file, w->line, w->func); printf("while(%s) with a variable that is %d!\n", w->str, val); w->printed |= 2; return 0; } return val; } int while_int(struct while_data *w, int val) { if (!(w->printed & 1)) { w->next = while_data_head; while_data_head = w; w->signd = true; const char* decrstr = strstr(w->str, "--"); if (decrstr != NULL) { if (strcmp(decrstr, "--") == 0) { w->incr = false; w->postfix = true; } else if (strcmp(decrstr, w->str) == 0) { /* FIXME: we have to ensure that the first part is a variable name and nothing else */ w->incr = false; w->postfix = false; } else { printf("decrement not recognized.\n"); } } else printf("no decrement found.\n"); w->printed |= 1; } /* other test for wrapping here */ return val; } #define __while_check__(x) ({ \ static struct while_data ______w = { \ .func = __func__, \ .file = __FILE__, \ .str = #x, \ .line = __LINE__, \ .last = ULONG_MAX, \ .printed = 0, \ }; \ __builtin_choose_expr( \ __builtin_constant_p(x), \ (x), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(x), int), \ while_int(&______w, (x)), \ __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(x), unsigned), \ while_unsigned(&______w, (x)), \ (x) \ ))); \ }) #define while(x) while(__while_check__(x)) int check_if(int val, const char* test, const char* func, int line) { struct while_data *w = while_data_head; if (strcmp(func, while_data_head->func) != 0) goto end; /* FIXME: we have to verify that the variable to the left is the same as the one used in the while loop */ /* TODO: also test "!= 0", "== 0" (and variants)*/ if (w->incr ) { if(w->postfix) { if (w->signd) { ; } else { ; } } else { if (w->signd) { ; } else { ; } } } else { if(w->postfix) { if (w->signd) { if (strstr(test, "< 0") != 0) { printf("after while(%s) at %s:%u:%s()\n", w->str, w->file, w->line, w->func); printf("if(%s) at line %u is off by one.\n", test, line); } else if (strstr(test, ">= 0") != 0){ printf("after while(%s) at %s:%u:%s()\n", w->str, w->file, w->line, w->func); printf("if(%s) at line %u is off by one.\n", test, line); } } else { if (strstr(test, "< 0") != 0) { printf("if(%s) at line %u is always false, since variable is unsigned.\n", test, line); } else if (strstr(test, ">= 0") != 0){ printf("if(%s) at line %u is always true, since variable is unsigned.\n", test, line); } } } else { if (w->signd) { if (strstr(test, "<= 0") != 0) { printf("after while(%s) at %s:%u:%s()\n", w->str, w->file, w->line, w->func); printf("if(%s) at line %u is off by one.\n", test, line); } else if (strstr(test, "> 0") != 0){ printf("after while(%s) at %s:%u:%s()\n", w->str, w->file, w->line, w->func); printf("if(%s) at line %u is off by one.\n", test, line); } } else { if (strstr(test, "< 0") != 0) { printf("if(%s) at line %u is always false, since variable is unsigned.\n", test, line); } else if (strstr(test, ">= 0") != 0){ printf("if(%s) at line %u is always true, since variable is unsigned.\n", test, line); } else if (strstr(test, "> 0") != 0){ printf("if(%s) at line %u is off by one.\n", test, line); } } } } end: return val; } #define __if_check__(x) ({ \ check_if((x), #x, __func__, __LINE__); \ }) #define if(x) if(__if_check__(x)) int main(int argc, char* argv[]) { //#define x 0 unsigned x = 10; int y; // these alternatives, should work while (x--) /*printf("in loop:%d\n", x)*/; if (x < 0) printf("won't print!\n"); x = 10; while (--x) /*printf("in loop:%d\n", x)*/; printf("after loop:%d\n", x); if (x < 0) printf("won't print!\n"); y = 10; while (y--) /*printf("in loop:%d\n", x)*/; if (y < 0) printf("will print.\n"); y = 10; while (--y) /*printf("in loop:%d\n", x)*/; if (y < 0) printf("won't print!\n"); return 0; } ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2009-03-11 19:16 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-03-08 4:22 Observe wrapping variables in while loops Roel Kluin 2009-03-09 16:20 ` Steven Rostedt 2009-03-11 19:16 ` Roel Kluin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox