Welcome to the Builder Academy

Question Segmentation Fault.

More
21 Feb 2019 02:48 #8320 by timeba
Segmentation Fault. was created by timeba
Hey guys, first time poster here. I'm pretty new to the C language but have moderate experience with php.

I have run into a segmentation fault when my user logs into the game.

The section of code where the error is located [comm.c:2631] is stock code that looks unchanged from the source. This mud is heavily customized (graphical interface and mysql db) and I recently became the new admin of it (nostalgia lol).

I followed the guide that you guys have posted here and attached my gdb output, if anyone is willing to help point me in the right direction I would greatly appreciate it!

Feb 21 02:28:06 :: Time (level 34) has 21 objects (max 30).

Program received signal SIGSEGV, Segmentation fault.
0x0000555555593f75 in perform_act (orig=0x5555555e24b1 "c >", ch=0x55555606aed0, obj=0x0, vict_obj=0x0, to=0x55555606aed0) at comm.c:2631
warning: Source file is more recent than executable.
2631 while ((*buf = *(i++)))
(gdb) bt
#0 0x0000555555593f75 in perform_act (orig=0x5555555e24b1 "c >", ch=0x55555606aed0, obj=0x0, vict_obj=0x0, to=0x55555606aed0) at comm.c:2631
#1 0x00005555555b2add in nanny (d=0x555556069150, arg=<optimized out>) at interpreter.c:1858
#2 0x00005555555972db in game_loop (mother_desc=3) at comm.c:768
#3 0x0000555555597516 in init_game (port=<optimized out>) at comm.c:385
#4 0x00005555555613c6 in main (argc=2, argv=<optimized out>) at comm.c:332
(gdb) list
2626 log("SYSERR: Illegal $-code to act(): %c", *orig);
2627 log("SYSERR: %s", orig);
2628 i = "";
2629 break;
2630 }
2631 while ((*buf = *(i++)))
2632 {
2633 if (uppercasenext && !isspace((int) *buf))
2634 {
2635 *buf = UPPER(*buf);
(gdb) info local
k = "\033\336\377\377\377\177\000\000\301\274\377\377\377\177\000\000\033\336\377\377"
i = 0x1 <error: Cannot access memory at address 0x1>
lbuf = "<art ~ save\000en;drink canteen;drink canteen;eat waybread", '\000' <repeats 25 times>, "\340\276\377\377\377\177\000\000$\016\362\366\377\177\000\000p\275\377\377\377\177\000\000$\016\362\366\377\177\000\000\vh\b\000\000\000\000\000\005", '\000' <repeats 31 times>, "\300b\322UUU\000\000\001\000\000\000\000\000\000\000z\026\\UUU\000\000\340\276\377\377\377\177\000\000\a\335\\UUU\000\000\001\000\000\000\000\000\000\000"...
buf = 0x7fffffffbcc7 "save"
j = <optimized out>
uppercasenext = 0 '\000'
(gdb) up
#1 0x00005555555b2add in nanny (d=0x555556069150, arg=<optimized out>) at interpreter.c:1858
1858 act("<art ~ $c >", FALSE, d->character, 0, 0, TO_CHAR);
(gdb) list
1853 GET_LOADROOM(d->character) = NOWHERE;
1854
1855 // save_char(d->character); // orig location, moving to AFTER NEWBIE CREATION -- heebie apr 22, 2013
1856
1857 act("<cha $x $h $i ~ $c ~ enters game $n ~ $z>", TRUE, d->character, 0, 0, TO_ROOM);
1858 act("<art ~ $c >", FALSE, d->character, 0, 0, TO_CHAR);
1859
1860 /* Put to sleep if they are affected. */
1861 if (AFF_FLAGGED(d->character, AFF_SLEEP)) {
1862 send_to_char(d->character,"<sleep>\r\n");
(gdb) info local
load_room = <optimized out>
load_result = 1
dt = <optimized out>
clan_num = <optimized out>
i = 0
(gdb) up
#2 0x00005555555972db in game_loop (mother_desc=3) at comm.c:768
768 nanny(d, comm);
(gdb) list
763 string_add(d, comm);
764 else if (d->showstr_count) /* Reading something w/ pager */
765 show_string(d, comm);
766 else if (STATE(d) != CON_PLAYING) { /* In menus, etc. */
767 // mudlog(CMP, LVL_GRGOD, TRUE, "calling nanny on socket d comm.c line 767 ");
768 nanny(d, comm);
769 }
770 else { /* else: we're playing normally. */
771 if (aliased) /* To prevent recursive aliases. */
772 d->has_prompt = 1; /* To get newline before next cmd output. */
(gdb) info local
input_set = {__fds_bits = {32, 0 <repeats 15 times>}}
output_set = {__fds_bits = {32, 0 <repeats 15 times>}}
exc_set = {__fds_bits = {0 <repeats 16 times>}}
null_set = {__fds_bits = {0 <repeats 16 times>}}
last_time = {tv_sec = 1550716083, tv_usec = 70878}
opt_time = {tv_sec = 0, tv_usec = 100000}
process_time = {tv_sec = 0, tv_usec = 144}
temp_time = {tv_sec = 0, tv_usec = 99856}
before_sleep = {tv_sec = 1550716082, tv_usec = 971022}
now = {tv_sec = 1550716083, tv_usec = 71585}
timeout = {tv_sec = 0, tv_usec = 0}
comm = "1\000me\000aOqIl14\000\177\000\000 \233\036\367\377\177\000\000 \233\036\367\377\177\000\000\320\342\377\377\377\177\000\000r\203]UUU\000\000\060\fn\\\000\000\000\000\000\344i\004\061i\214\032\000\000\000\000\000\000\000\000\003\000\000\000\000\000\000\000@\255^UUU\000\000\220\037\000\000\000\000\000\000\260\343\377\377\377\177\000\000S\204]UUU\000\000\b\000\000\000\060\000\000\000\300\343\377\377\377\177\000\000\000\343\377\377\377\177\000\000\000\344i\004\061i\214\032\320\341\377\377\377\177\000\000\320\340\377\377\377\177\000\000\000\000\000\000\000\000\000\000G\335\360\366\377\177\000\000\300\342\377\377\377\177\000\000\300\242\376\367\377\177\000\000\001\000\000\000\000\000\000\000"...
d = 0x555556069150
next_d = 0x0
pulse = <optimized out>
missed_pulses = 0
maxdesc = <optimized out>
aliased = 0
(gdb) up
#3 0x0000555555597516 in init_game (port=<optimized out>) at comm.c:385
385 game_loop(mother_desc);
(gdb) list
380 /* If we made it this far, we will be able to restart without problem. */
381 remove(KILLSCRIPT_FILE);
382
383 log("Entering game loop.");
384
385 game_loop(mother_desc);
386
387 Crash_save_all();
388 //House_save_all(); /* obsolete - SMD 2007-01-16 */
389
(gdb) info local
mother_desc = 3
(gdb) up
#4 0x00005555555613c6 in main (argc=2, argv=<optimized out>) at comm.c:332
332 init_game(port);
(gdb) list
327
328 if (scheck)
329 boot_world();
330 else {
331 log("Running game on port %d.", port);
332 init_game(port);
333 }
334
335 log("Clearing game world.");
336 destroy_db();
(gdb) info local
port = 8080
pos = <optimized out>
dir = 0x5555555ead40 "lib"
(gdb) up
Initial frame selected; you cannot go up.

Please Log in or Create an account to join the conversation.

More
21 Feb 2019 12:08 #8322 by cunning
Replied by cunning on topic Segmentation Fault.
I only have one issue with this, your source code is newer than your executable. This can give false output when debugging. I am not sure this is your actual crash bug.

Please Log in or Create an account to join the conversation.

More
22 Feb 2019 00:26 #8323 by timeba
Replied by timeba on topic Segmentation Fault.
Thanks for the reply, I removed bin/circle and then recompiled

gcc -o ../bin/circle -pg act.comm.o act.informative.o act.item.o act.movement.o act.offensive.o act.other.o act.social.o act.wizard.o alias.o ban.o boards.o castle.o clan.o class.o comm.o config.o constants.o db.o fight.o graph.o handler.o house.o interpreter.o limits.o magic.o mail.o mobact.o mob_skills.o modify.o objsave.o olc.o races.o random.o shop.o skills.o spec_assign.o spec_procs.o spell_parser.o spells.o statedit.o utils.o weather.o bsd-snprintf.o -lcrypt -lmysqlclient -lm
make[1]: Leaving directory '/home/mud-service/BA-live/src'
make utils
make[1]: Entering directory '/home/mud-service/BA-live/src'
(cd util; make all)
make[2]: Entering directory '/home/mud-service/BA-live/src/util'
make[2]: Nothing to be done for 'all'.
make[2]: Leaving directory '/home/mud-service/BA-live/src/util'
make[1]: Leaving directory '/home/mud-service/BA-live/src'


Then I ran it under gdb again:

...
Feb 21 23:55:13 :: Resetting #501: Yucca Processing Plant (rooms 50100-50199).
Feb 21 23:55:13 :: Resetting #600: Test zone (rooms 60000-60099).
Feb 21 23:55:13 :: Boot db -- DONE.
Feb 21 23:55:13 :: Signal trapping.
Feb 21 23:55:13 :: Entering game loop.
Feb 21 23:55:13 :: No connections. Going to sleep.
Feb 22 00:13:29 :: New connection. Waking up.
Feb 22 00:13:31 :: timeba [desktop] has connected.
Feb 22 00:14:18 :: timeba logged on as Time [desktop].
Feb 22 00:14:53 :: Time (level 80) has 29 objects (max 30).

Program received signal SIGSEGV, Segmentation fault.
0x0000555555593f85 in perform_act (orig=0x5555555e24b1 "c >",
ch=0x555556067330, obj=0x0, vict_obj=0x0, to=0x555556067330) at comm.c:2631
2631 while ((*buf = *(i++)))
(gdb) bt
#0 0x0000555555593f85 in perform_act (orig=0x5555555e24b1 "c >",
ch=0x555556067330, obj=0x0, vict_obj=0x0, to=0x555556067330) at comm.c:2631
#1 0x00005555555b2aed in nanny (d=0x5555560655b0, arg=<optimized out>)
at interpreter.c:1858
#2 0x00005555555972eb in game_loop (mother_desc=3) at comm.c:768
#3 0x0000555555597526 in init_game (port=<optimized out>) at comm.c:385
#4 0x00005555555613c6 in main (argc=2, argv=<optimized out>) at comm.c:332
(gdb) info local
k = "gain.\000\000\000\301\274\377\377\377\177\000\000\033\336\377\377"
i = 0x1 <error: Cannot access memory at address 0x1>
lbuf = "<art ~ save\000en;drink canteen;drink canteen;eat waybread", '\000' <repeats 25 times>, "\340\276\377\377\377\177\000\000$\016\362\366\377\177\000\000p\275\377\377\377\177\000\000$\016\362\366\377\177\000\000\vh\b\000\000\000\000\000\005", '\000' <repeats 31 times>, "\300b\322UUU\000\000\001\000\000\000\000\000\000\000\212\026\\UUU\000\000\340\276\377\377\377\177\000\000\027\335\\UUU\000\000\001\000\000\000\000\000\000\000"...
buf = 0x7fffffffbcc7 "save"
j = <optimized out>
uppercasenext = 0 '\000'
(gdb) list
2626 log("SYSERR: Illegal $-code to act(): %c", *orig);
2627 log("SYSERR: %s", orig);
2628 i = "";
2629 break;
2630 }
2631 while ((*buf = *(i++)))
2632 {
2633 if (uppercasenext && !isspace((int) *buf))
2634 {
2635 *buf = UPPER(*buf);
(gdb) print
The history is empty.
(gdb) up
#1 0x00005555555b2aed in nanny (d=0x5555560655b0, arg=<optimized out>)
at interpreter.c:1858
1858 act("<art ~ $c >", FALSE, d->character, 0, 0, TO_CHAR);
(gdb) info local
load_room = <optimized out>
load_result = 1
dt = <optimized out>
clan_num = <optimized out>
i = 0
(gdb) list
1853 GET_LOADROOM(d->character) = NOWHERE;
1854
1855 // save_char(d->character); // orig location, moving to AFTER NEWBIE CREATION -- heebie apr 22, 2013
1856
1857 act("<cha $x $h $i ~ $c ~ enters game $n ~ $z>", TRUE, d->character, 0, 0, TO_ROOM);
1858 act("<art ~ $c >", FALSE, d->character, 0, 0, TO_CHAR);
1859
1860 /* Put to sleep if they are affected. */
1861 if (AFF_FLAGGED(d->character, AFF_SLEEP)) {
1862 send_to_char(d->character,"<sleep>\r\n");
(gdb) print
The history is empty.
(gdb) up
#2 0x00005555555972eb in game_loop (mother_desc=3) at comm.c:768
768 nanny(d, comm);
(gdb) info local
input_set = {__fds_bits = {32, 0 <repeats 15 times>}}
output_set = {__fds_bits = {32, 0 <repeats 15 times>}}
exc_set = {__fds_bits = {0 <repeats 16 times>}}
null_set = {__fds_bits = {0 <repeats 16 times>}}
last_time = {tv_sec = 1550794474, tv_usec = 94559}
opt_time = {tv_sec = 0, tv_usec = 100000}
process_time = {tv_sec = 0, tv_usec = 8204}
temp_time = {tv_sec = 0, tv_usec = 91796}
before_sleep = {tv_sec = 1550794474, tv_usec = 2763}
now = {tv_sec = 1550794474, tv_usec = 95503}
timeout = {tv_sec = 0, tv_usec = 0}
comm = "1\000me\000aOqIl14\000\177\000\000 \233\036\367\377\177\000\000 \233\036\367\377\177\000\000\320\342\377\377\377\177\000\000\202\203]UUU\000\000a:o\\\000\000\000\000\000zfz$\256\"}\000\000\000\000\000\000\000\000\003\000\000\000\000\000\000\000@\255^UUU\000\000\220\037\000\000\000\000\000\000\260\343\377\377\377\177\000\000c\204]UUU\000\000\b\000\000\000\060\000\000\000\300\343\377\377\377\177\000\000\000\343\377\377\377\177\000\000\000zfz$\256\"}\320\341\377\377\377\177\000\000\320\340\377\377\377\177\000\000\000\000\000\000\000\000\000\000G\335\360\366\377\177\000\000\300\342\377\377\377\177\000\000\300\242\376\367\377\177\000\000\001\000\000\000\000\000\000\000"...
d = 0x5555560655b0
next_d = 0x0
pulse = <optimized out>
---Type <return> to continue, or q <return> to quit---
missed_pulses = 0
maxdesc = <optimized out>
aliased = 0
(gdb) list
763 string_add(d, comm);
764 else if (d->showstr_count) /* Reading something w/ pager */
765 show_string(d, comm);
766 else if (STATE(d) != CON_PLAYING) { /* In menus, etc. */
767 // mudlog(CMP, LVL_GRGOD, TRUE, "calling nanny on socket d comm.c line 767 ");
768 nanny(d, comm);
769 }
770 else { /* else: we're playing normally. */
771 if (aliased) /* To prevent recursive aliases. */
772 d->has_prompt = 1; /* To get newline before next cmd output. */
(gdb) print
The history is empty.
(gdb) up
#3 0x0000555555597526 in init_game (port=<optimized out>) at comm.c:385
385 game_loop(mother_desc);
(gdb) info local
mother_desc = 3
(gdb) list
380 /* If we made it this far, we will be able to restart without problem. */
381 remove(KILLSCRIPT_FILE);
382
383 log("Entering game loop.");
384
385 game_loop(mother_desc);
386
387 Crash_save_all();
388 //House_save_all(); /* obsolete - SMD 2007-01-16 */
389
(gdb) print
The history is empty.
(gdb) up
#4 0x00005555555613c6 in main (argc=2, argv=<optimized out>) at comm.c:332
332 init_game(port);
(gdb) info local
port = 8080
pos = <optimized out>
dir = 0x5555555ead40 "lib"
(gdb) list
327
328 if (scheck)
329 boot_world();
330 else {
331 log("Running game on port %d.", port);
332 init_game(port);
333 }
334
335 log("Clearing game world.");
336 destroy_db();
(gdb) print
The history is empty.
(gdb) up
Initial frame selected; you cannot go up.
(gdb)

Please Log in or Create an account to join the conversation.

More
23 Feb 2019 11:57 - 23 Feb 2019 11:58 #8328 by thomas
Replied by thomas on topic Segmentation Fault.
Well, somethings up with the i variable.

Code:
i = 0x1 <error: Cannot access memory at address 0x1>

i should never be 1. It should either point to NULL or it should point to an empty string (if you pass it an unknown $code or a code with no "string" meaning).
So, we've hit the $c case in perform_act. And that isn't a stock code. Which means that we'll need a bit more info.

What happens in case 'c': ? And please show the expansion of any macros in use there.
Last edit: 23 Feb 2019 11:58 by thomas.

Please Log in or Create an account to join the conversation.

More
24 Feb 2019 02:27 - 24 Feb 2019 02:33 #8329 by timeba
Replied by timeba on topic Segmentation Fault.
Appreciate the help!

Looks like that section of code is getting the artwork for the GUI.

Here is the section from the gdb error:

const char *ACTNULL = "<NULL>";

#define CHECK_NULL(pointer, expression) \
if ((pointer) == NULL) i = ACTNULL; else i = (expression);

/* higher-level communication: the act() function */
void perform_act(const char *orig, struct char_data *ch, struct obj_data *obj,
const void *vict_obj, const struct char_data *to)
{
char k[20];
const char *i = NULL;
char lbuf[MAX_STRING_LENGTH], *buf, *j;
bool uppercasenext = FALSE;

buf = lbuf;

for (;;) {
if (*orig == '$') {
switch (*(++orig)) {
case 'r': /* get random number */
sprintf(k, "%i", rand_number(1, 9999999));
i = k;
break;
case 'c': /* get character art */
i = get_art(ch);
break;
case 'C': /* get victim art */
i = get_art((struct char_data *) vict_obj);
break;
case 'z': /* affects */


here is the section for *get_art from line 1483 in handler.c:

char *get_art(struct char_data *vict) {
char buf[200];
char *fbuf = buf;
int art_num;
int count;

if (IS_NPC(vict))
art_num = GET_MOB_ART(vict);
else
art_num = GET_PLAYER_ART(vict);


count = sprintf(buf, "%d %d %d", art_num,
GET_RACE(vict), GET_SEX(vict));

/* equipment */
if (!IS_NPC(vict) || MOB_FLAGGED(vict, MOB_SHOW_EQ)) {
/* light */
// if (GET_EQ(vict, WEAR_LIGHT))
// count += sprintf(buf + count, " %d",
// GET_OBJ_ART(GET_EQ(vict, WEAR_LIGHT)));
// else
// count += sprintf(buf + count, " %d", 0);
/* body */
if (GET_EQ(vict, WEAR_BODY))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_BODY)));
else
count += sprintf(buf + count, " %d", 0);
/* head */
if (GET_EQ(vict, WEAR_HEAD))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_HEAD)));
else
count += sprintf(buf + count, " %d", 0);
/* legs */
if (GET_EQ(vict, WEAR_LEGS))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_LEGS)));
else
count += sprintf(buf + count, " %d", 0);
/* feet */
if (GET_EQ(vict, WEAR_FEET))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_FEET)));
else
count += sprintf(buf + count, " %d", 0);
/* hands */
if (GET_EQ(vict, WEAR_HANDS))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_HANDS)));
else
count += sprintf(buf + count, " %d", 0);
/* arms */
if (GET_EQ(vict, WEAR_ARMS))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_ARMS)));
else
count += sprintf(buf + count, " %d", 0);
/* shield */
if (GET_EQ(vict, WEAR_SHIELD))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_SHIELD)));
else
count += sprintf(buf + count, " %d", 0);
/* about */
if (GET_EQ(vict, WEAR_ABOUT))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_ABOUT)));
else
count += sprintf(buf + count, " %d", 0);
/* wield */
if (GET_EQ(vict, WEAR_WIELD))
count += sprintf(buf + count, " %d",
GET_OBJ_ART(GET_EQ(vict, WEAR_WIELD)));
else
count += sprintf(buf + count, " %d", 0);
/* hold */
// if (GET_EQ(vict, WEAR_HOLD))
// count += sprintf(buf + count, " %d",
// GET_OBJ_ART(GET_EQ(vict, WEAR_HOLD)));
// else
// count += sprintf(buf + count, " %d", 0);
/* tattoo */
if (!IS_NPC(vict) && GET_CLAN_RANK(vict))
count += sprintf(buf + count, " %d", GET_CLAN(vict));
else
count += sprintf(buf + count, " %d", 0);
}

return fbuf;
}


here is another on line 79 in handler.h:

char *get_art(struct char_data *ch);


here is another reference to get_art in db.c on line 546:

result = mysql_store_result(db_handle);
if ((row = mysql_fetch_row(result))) { /* update */
char *i, *k;
char j[200];
k = j;
i = get_art(d->character);
while ((*k = *(i++))) k++;


The art located in the mysql db for character Time is
Code:
1409 0 1 150532 171205 171959 150801 170762 152159 2556 1453 170023 0

I get the same issue with other characters so I don't believe it is specific to the one character (Time).
Last edit: 24 Feb 2019 02:33 by timeba. Reason: formatting

Please Log in or Create an account to join the conversation.

More
24 Feb 2019 11:37 #8330 by thomas
Replied by thomas on topic Segmentation Fault.
Your culprit is the get_art() function. The moment you exit such a function, every allocated buffer is released for reuse, unless it is a static buffer.

So, instead of
Code:
char *get_art(struct char_data *vict) { char buf[200]; char *fbuf = buf; // code writing to buf return fbuf; }
Try this:
Code:
char *get_art(struct char_data *vict) { static char buf[200]; *buf = '\0'; // code writing to buf return buf; }
This will allocate the buf variable in another memory section, and it will be reused for all calls to the get_art() function.

Also, please format your code with [ code ] tags instead of [ quote ] tags :P

Please Log in or Create an account to join the conversation.

Time to create page: 0.517 seconds