All of lore.kernel.org
 help / color / mirror / Atom feed
From: Roel Kluin <roel.kluin@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: lkml <linux-kernel@vger.kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>
Subject: Re: Observe wrapping variables in while loops
Date: Wed, 11 Mar 2009 20:16:06 +0100	[thread overview]
Message-ID: <49B80DF6.6070407@gmail.com> (raw)
In-Reply-To: <alpine.DEB.2.00.0903091119090.2203@gandalf.stny.rr.com>

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;
}


      reply	other threads:[~2009-03-11 19:16 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=49B80DF6.6070407@gmail.com \
    --to=roel.kluin@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.