Angband.oook.cz
Angband.oook.cz
AboutVariantsLadderForumCompetitionComicScreenshotsFunniesLinks

Go Back   Angband Forums > Angband > Development

Reply
 
Thread Tools Display Modes
Old February 18, 2015, 18:47   #1
chris
PosChengband Maintainer
 
Join Date: Jan 2008
Posts: 702
chris is on a distinguished road
Macro Help

(or, why does GCC keep complaining at me?)

So, I'm trying to do a good thing and look into warnings when compiling poschengband on gcc. I'm not really a C developer, so I don't really know what I am doing!

Anyway, some warnings have me stumped. First, is this:
Code:
cmd1.c:2492:29: warning: comparison is always false due to limited range of data type [-Wtype-limits]
     if (prace_is_(MIMIC_BAT))
The macro prace_is_ is defined as follows:
Code:
#define prace_is_(A) (p_ptr->mimic_form == (A) || (p_ptr->mimic_form == MIMIC_NONE && (A) < MAX_RACES && p_ptr->prace == (A)))
where mimic_form is an s16b and prace is a byte. MIMIC_BAT is indeed outside the range of prace as it is over 1000 so could have been problematic before I added the "(A) < MAX_RACES" check to the macro.

Expanding the macro manually gives a warning as well:
Code:
    if (p_ptr->mimic_form == MIMIC_BAT || (p_ptr->mimic_form == MIMIC_NONE && MIMIC_BAT < MAX_RACES && p_ptr->prace == MIMIC_BAT))
        return 100;
The code works correctly, and as far as I can tell, is coded correctly. There is no chance of comparing prace vs MIMIC_BAT. But even if there was, I don't get the comparison is always false claim. It defintely will return true if mimic_form is set to MIMIC_BAT!

So, is the macro incorrect? I inherited the mixed data sizes from Hengband and would rather not make prace an s16b.

Thanks!

EDIT: I think the warning actually applies only to the p_ptr->prace == (A) comparison, even though that conditional is unreachable in the case A exceeds the storage limits of a byte. Also, gcc is flagging the "if" as the point of the error, rather than the comparison, which is highly confusing. So, for example, changing from a macro to something like:
Code:
bool prace_is_(int which)
{
    if (p_ptr->mimic_form == which)
        return TRUE;
    else if (p_ptr->mimic_form == MIMIC_NONE && p_ptr->prace == which)
            return TRUE;
    return FALSE;
}
fixes the problem.

Last edited by chris; February 18, 2015 at 19:21.
chris is offline   Reply With Quote
Old February 19, 2015, 01:41   #2
chris
PosChengband Maintainer
 
Join Date: Jan 2008
Posts: 702
chris is on a distinguished road
Ah, good times. Learning to debug on Linux and what better way to cut my teeth than attempting to mod main-gcu.c. Subtle changes to the map display size are now causing stack stompage. Eventually, after about 4 hours, I discover this:

Code:
diff --git a/src/main-gcu.c b/src/main-gcu.c
index 18606dd..e018ae3 100644
--- a/src/main-gcu.c
+++ b/src/main-gcu.c
 
@@ -1094,7 +1094,7 @@ static errr Term_text_gcu(int x, int y, int n, byte a, cptr s)
 
    int i;
 
-   char text[81];
+   char text[1024];
I was wondering why 80x24 was hardcoded all over the place ...
chris is offline   Reply With Quote
Old February 19, 2015, 09:16   #3
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by chris View Post
Ah, good times. Learning to debug on Linux and what better way to cut my teeth than attempting to mod main-gcu.c. Subtle changes to the map display size are now causing stack stompage. Eventually, after about 4 hours, I discover this:

Code:
diff --git a/src/main-gcu.c b/src/main-gcu.c
index 18606dd..e018ae3 100644
--- a/src/main-gcu.c
+++ b/src/main-gcu.c
 
@@ -1094,7 +1094,7 @@ static errr Term_text_gcu(int x, int y, int n, byte a, cptr s)
 
    int i;
 
-   char text[81];
+   char text[1024];
I was wondering why 80x24 was hardcoded all over the place ...
If you're not already doing so, you NEED to start using ASAN (Address Sanitizer) when compiling (works for both clang and gcc). Other tools from the same "suite" of flags may also be helpful, but even just ASAN catches a LOT of these problems early on and very often gives you the exact location of the origin of the problem. See the "-fsanitize" family of gcc/clang command line options for details. It takes literally less than 5 minutes to get started and it'll save you from a lot of guessing and flailing around in the dark.

EDIT: I should say that ASAN+... are runtime instrumentation, so you'll actually need to run the game and play a bit, but that sure as hell beats mucking around in ancient C code .
AnonymousHero is offline   Reply With Quote
Old February 19, 2015, 23:32   #4
chris
PosChengband Maintainer
 
Join Date: Jan 2008
Posts: 702
chris is on a distinguished road
Apologies for posting in the wrong thread before. I was asking for help with linux -fsanitize.

Quote:
(On a tablet, so forgive the brevity)

Output: there may be an option or env variable you can set to force sanitizer output to a file. If not, I'm pretty sure you can just redirect stderr to a file, eg using "2>&1 myfile" as the last part of the command line. (The reason the output is mangled is that ncurses disables newlines on the terminal.)

About the missing "undefined": see the gcc manual, i was workingfrom memory and the option may be a little different, something to do with "undefined behavior". It's possible that the option wasn't available in gcc 4.8.

Generally i'd recommend clang when using the sanitizer since it usually has more recent support. (And is mostly cmdline compatible with gcc.)
Thanks. gcc 4.9 got -fsanitize=undefined but hasn't been released yet on Mint. I managed to upgrade, though.

For the record, I've had a lot of problems finding documentation. The gcc manual barely mentions these options. Eventually, I found this. I've never heard of clang before. Is this a substitute for gcc?

Thanks, again for your patience.

Edit: I just found this as well.
chris is offline   Reply With Quote
Old February 20, 2015, 06:25   #5
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by chris View Post
Apologies for posting in the wrong thread before. I was asking for help with linux -fsanitize.



Thanks. gcc 4.9 got -fsanitize=undefined but hasn't been released yet on Mint. I managed to upgrade, though.

For the record, I've had a lot of problems finding documentation. The gcc manual barely mentions these options. Eventually, I found this. I've never heard of clang before. Is this a substitute for gcc?
clang is a completely different C/C++ compiler. It's mostly command-line compatible with gcc -- for the common options at least. You should basically be able to replace "gcc" with "clang" in your compilation command line.

Quote:
Originally Posted by chris View Post
Edit: I just found this as well.
Ah, yes, looks like you'd want something like
Code:
ASAN_OPTIONS=log_path=asan_log ./poschengband
(and then look in asan_log.XXX for the output, obviously) to avoid messing up the terminal. Or, as mentioned in the other thread, just redirect stderr to a file by running
Code:
./poschengband 2> asan.log
HTH.
AnonymousHero is offline   Reply With Quote
Old February 25, 2015, 22:17   #6
chris
PosChengband Maintainer
 
Join Date: Jan 2008
Posts: 702
chris is on a distinguished road
Chris' Linux Development Q&A Thread

OK, thanks again for tips.

Today I learned that the "escape delay" on the curses port has nothing whatsoever to do with ESCDELAY in curses. Not a thing! It actually has to do with multi-character macros setup in pref-gcu.pref to map the multi-character sequences that curses generates for certain keystrokes. Like, you press '2' on the num pad and curses sends \e[B (3 calls to getch()). pref-gcu.pref sets up a macro to translate this back to '2' for the game engine. Now, when the user presses \e (say, to dismiss a menu), our code (not curses!) is pausing to see if the user really wants to type \e[B by hand! Fun stuff, I just had to share

Anyway, today's question relates to setting up compiler options in the build. For instance, if I want -fsanitize=address to be set, then this should only happen for me, not for other people who download and compile on linux (as they may use an older gcc or some other compiler). What I came up with was doing a
Code:
./configure CFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address --with-no-install
which is a bit cumbersome. Is there a better way?

On a similar note, sometimes I want a debug build (-O0 -g) and sometimes not (-O3). I gather that changing src/Makefile (which is under version control) is not the best way to do this ... Help?

Thanks in advance!
chris is offline   Reply With Quote
Old February 25, 2015, 22:40   #7
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by chris View Post
OK, thanks again for tips.

Today I learned that the "escape delay" on the curses port has nothing whatsoever to do with ESCDELAY in curses. Not a thing! It actually has to do with multi-character macros setup in pref-gcu.pref to map the multi-character sequences that curses generates for certain keystrokes. Like, you press '2' on the num pad and curses sends \e[B (3 calls to getch()). pref-gcu.pref sets up a macro to translate this back to '2' for the game engine. Now, when the user presses \e (say, to dismiss a menu), our code (not curses!) is pausing to see if the user really wants to type \e[B by hand! Fun stuff, I just had to share
Yeah, maddening, isn't it? The input/macro/keymap system is truly bizarre -- just people adding onto other people's work without any true understanding, just hacking until "it works". (I'm going by the probably-reasonable assumption that Hengband's system is similar to Zangband's which is probably similar to ToME 2.x.)

Quote:
Originally Posted by chris View Post
Anyway, today's question relates to setting up compiler options in the build. For instance, if I want -fsanitize=address to be set, then this should only happen for me, not for other people who download and compile on linux (as they may use an older gcc or some other compiler). What I came up with was doing a
Code:
./configure CFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address --with-no-install
which is a bit cumbersome. Is there a better way?

On a similar note, sometimes I want a debug build (-O0 -g) and sometimes not (-O3). I gather that changing src/Makefile (which is under version control) is not the best way to do this ... Help?
Personally, I wouldn't shy away from changing the Makefile. I just try to careful about what I merge (note: not "commit"). My workflow is usually heavily rebase-oriented so I just: a) branch, b) commit ad libitum (including makefile changes), c) commit some more (xN), d) rebase + squash branch appropriately on current master, e) excise undesirable parts of the squashed commit(s) using "git gui" (in amend mode) or "git rebase -i". And finally, f) merge (fast-forward, preferably).
AnonymousHero is offline   Reply With Quote
Old February 26, 2015, 04:31   #8
Nivim
Apprentice
 
Join Date: Jan 2014
Location: Sufficient for living and internet.
Posts: 69
Nivim is on a distinguished road
It's nice to finally know why there's that little hang; I'd really been curious about what the program was doing! So much so that even given a plethora of other possibilities, I feel like it was development time well spent.
Nivim is offline   Reply With Quote
Old April 19, 2015, 19:02   #9
chris
PosChengband Maintainer
 
Join Date: Jan 2008
Posts: 702
chris is on a distinguished road
Help? I can't seem to figure out why I stopped getting symbols in Address Sanitizer output when using clang as my compiler.

What I am doing:
Code:
./configure CFLAGS=-fsanitize=address LDFLAGS=-fsanitize=address --with-no-install CC=clang-3.5
and in Makefile:
Code:
CFLAGS += -DBUILD_ID=${VERSION} -I. -std=c99 -Wdeclaration-after-statement -O0 -g -fno-omit-frame-pointer
Now, if I drop the CC=clang-3.5 from my configure, and just use gcc, I get symbols. However, my gcc does not do leak detection and clang-3.5 does, so I'd like to be able to use that if possible.

The symbols must be in the executable, since clang barfs out a 25Mb file (versus 9 for gcc). However, I can't figure out what I might be missing.

Thanks for any help!

(FYI: Address sanitizer does not detect out of bounds stuff for arrays inside the middle of structs.)

EDIT: If I do exactly what is suggested here at the top, I don't get symbols either. So, how to get symbols with clang might be my problem:
Code:
> cat leak.c
#include <stdlib.h>

void *p;

int main() {
  p = malloc(7);
  p = 0; // The memory is leaked here.
  return 0;
}
> clang-3.5 -fsanitize=address -g leak.c
> ./a.out

=================================================================
==20475==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 7 byte(s) in 1 object(s) allocated from:
    #0 0x49a13b (/home/chris/Src/poschengband/src/a.out+0x49a13b)
    #1 0x4b79a0 (/home/chris/Src/poschengband/src/a.out+0x4b79a0)
    #2 0x7fcd376ceec4 (/lib/x86_64-linux-gnu/libc.so.6+0x21ec4)

SUMMARY: AddressSanitizer: 7 byte(s) leaked in 1 allocation(s).

EDIT2: Found answer here. Or an answer, anyway. Now I just need to remember to type:
Code:
./poschengband -g -uChris -- -n1 2>&1 | /tmp/asan_symbolize.py | c++filt
whenever I run

EDIT3: Better answer. Install llvm-3.5 package and run
Code:
ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.5 ./poschengband -g -uChris -- -n1
. I'm not sure that's any easier to type, though!

Last edited by chris; April 19, 2015 at 19:47.
chris is offline   Reply With Quote
Old April 19, 2015, 20:25   #10
AnonymousHero
Veteran
 
AnonymousHero's Avatar
 
Join Date: Jun 2007
Posts: 1,367
AnonymousHero is on a distinguished road
Quote:
Originally Posted by chris View Post
(FYI: Address sanitizer does not detect out of bounds stuff for arrays inside the middle of structs.)
Are you sure? I think it should be able to, unless the structs are packed for some reason. (Maybe it's version-dependent, I'm currently running clang 3.6.)

Quote:
Originally Posted by chris View Post
EDIT3: Better answer. Install llvm-3.5 package and run
Code:
ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.5 ./poschengband -g -uChris -- -n1
. I'm not sure that's any easier to type, though!
Sounds like bad packaging to me. I get symbol output by default without having to fiddle with ASAN_SYMBOLIZER_PATH or anything like that. (I'm pretty sure that was also the case with Clang 3.5.)

I guess you could always just add ASAN_SYMBOLIZER_PATH to your ~/.bash_profile (or whatever your shell is) so that you at least won't have to type all of that every time.
AnonymousHero is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
[3.4-RC] Macro problem PowerWyrm Vanilla 3 August 1, 2012 23:47
Tunneling macro help... Skitzman69 Vanilla 3 April 30, 2012 06:39
Macro help Raggy Vanilla 11 June 19, 2011 08:05
can't use @a1 inscription/macro fbas Vanilla 4 November 18, 2010 20:05
Macro difficulty stabbo Vanilla 16 November 18, 2010 08:16


All times are GMT +1. The time now is 02:05.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.