From 87c9e1db337767e6a19c69a907baeee57d171e45 Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Sat, 8 Jan 2005 19:00:46 +0000
Subject: [PATCH] Warn if flags is signed instead of unsigned (bug #3279)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4713 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 apps/app_queue.c           |  4 +-
 apps/app_voicemail.c       |  2 +-
 include/asterisk/channel.h |  4 +-
 include/asterisk/utils.h   | 81 +++++++++++++++++++++++++++++++-------
 4 files changed, 72 insertions(+), 19 deletions(-)

diff --git a/apps/app_queue.c b/apps/app_queue.c
index b78f947e02..ef7115db4a 100755
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -183,7 +183,7 @@ struct localuser {
 	int stillgoing;
 	int metric;
 	int oldstatus;
-	int flags;			/* flag bits */
+	unsigned int flags;		/* flag bits */
 	time_t lastcall;
 	struct member *member;
 	struct localuser *next;
@@ -224,7 +224,7 @@ struct ast_call_queue {
 	char moh[80];			/* Name of musiconhold to be used */
 	char announce[80];		/* Announcement to play when call is answered */
 	char context[80];		/* Context for this queue */
-	int flags;			/* flag bits */
+	unsigned int flags;		/* flag bits */
 	int strategy;			/* Queueing strategy */
 	int announcefrequency;          /* How often to announce their position */
 	int roundingseconds;            /* How many seconds do we round to? */
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index b4d4c9d0fa..d33259f614 100755
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -157,7 +157,7 @@ struct ast_vm_user {
 	char dialout[80];
 	char uniqueid[20];		/* Unique integer identifier */
 	char exit[80];
-	int flags;			/* VM_ flags */	
+	unsigned int flags;		/* VM_ flags */	
 	int saydurationm;
 	struct ast_vm_user *next;
 };
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 765e7ff4df..2bd38b2173 100755
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -218,7 +218,7 @@ struct ast_channel {
 	unsigned int pickupgroup;
 
 	/*! channel flags of AST_FLAG_ type */
-	int flags;
+	unsigned int flags;
 	
 	/*! For easy linking */
 	struct ast_channel *next;
@@ -251,7 +251,7 @@ struct ast_bridge_config {
 	char *end_sound;
 	char *start_sound;
 	int firstpass;
-	int flags;
+	unsigned int flags;
 };
 
 struct chanmon;
diff --git a/include/asterisk/utils.h b/include/asterisk/utils.h
index 9798543ba9..ff42c13128 100755
--- a/include/asterisk/utils.h
+++ b/include/asterisk/utils.h
@@ -18,19 +18,76 @@
 #include <asterisk/lock.h>
 #include <limits.h>
 
-#define ast_test_flag(p,flag) 		((p)->flags & (flag))
-
-#define ast_set_flag(p,flag)		((p)->flags |= (flag))
-
-#define ast_clear_flag(p,flag)		((p)->flags &= ~(flag))
-
-#define ast_copy_flags(dest,src,flagz)	do { (dest)->flags &= ~(flagz); \
-					(dest)->flags |= ((src)->flags & (flagz)); } while(0)
-
-#define ast_set2_flag(p,value,flag)	((value) ? ast_set_flag(p,flag) : ast_clear_flag(p,flag))	
+/* Note:
+   It is very important to use only unsigned variables to hold
+   bit flags, as otherwise you can fall prey to the compiler's
+   sign-extension antics if you try to use the top two bits in
+   your variable.
+
+   The flag macros below use a set of compiler tricks to verify
+   that the caller is using an "unsigned int" variable to hold
+   the flags, and nothing else. If the caller uses any other
+   type of variable, a warning message similar to this:
+
+   warning: comparison of distinct pointer types lacks cast
+
+   will be generated.
+
+   The "dummy" variable below is used to make these comparisons.
+
+   Also note that at -O2 or above, this type-safety checking
+   does _not_ produce any additional object code at all.
+*/
+
+extern unsigned int __unsigned_int_flags_dummy;
+
+#define ast_test_flag(p,flag) 		({ \
+					typeof ((p)->flags) __p = (p)->flags; \
+					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					(void) (&__p == &__x); \
+					((p)->flags & (flag)); \
+					})
+
+#define ast_set_flag(p,flag) 		do { \
+					typeof ((p)->flags) __p = (p)->flags; \
+					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					(void) (&__p == &__x); \
+					((p)->flags |= (flag)); \
+					} while(0)
+
+#define ast_clear_flag(p,flag) 		do { \
+					typeof ((p)->flags) __p = (p)->flags; \
+					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					(void) (&__p == &__x); \
+					((p)->flags &= ~(flag)); \
+					} while(0)
+
+#define ast_copy_flags(dest,src,flagz)	do { \
+					typeof ((dest)->flags) __d = (dest)->flags; \
+					typeof ((src)->flags) __s = (src)->flags; \
+					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					(void) (&__d == &__x); \
+					(void) (&__s == &__x); \
+					(dest)->flags &= ~(flagz); \
+					(dest)->flags |= ((src)->flags & (flagz)); \
+					} while (0)
+
+#define ast_set2_flag(p,value,flag)	do { \
+					typeof ((p)->flags) __p = (p)->flags; \
+					typeof (__unsigned_int_flags_dummy) __x = 0; \
+					(void) (&__p == &__x); \
+					if (value) \
+						(p)->flags |= (flag); \
+					else \
+						(p)->flags &= ~(flag); \
+					} while (0)
 
 #define AST_FLAGS_ALL UINT_MAX
 
+struct ast_flags {
+	unsigned int flags;
+};
+
 static inline int ast_strlen_zero(const char *s)
 {
 	return (*s == '\0');
@@ -41,10 +98,6 @@ struct ast_hostent {
 	char buf[1024];
 };
 
-struct ast_flags {
-	unsigned int flags;
-};
-
 extern char *ast_strip(char *buf);
 extern struct hostent *ast_gethostbyname(const char *host, struct ast_hostent *hp);
 extern int ast_base64encode(char *dst, unsigned char *src, int srclen, int max);
-- 
GitLab