?
Solved

Porting C code from Unix (SunOS) to Linux: are there malloc differences?

Posted on 2004-11-03
13
Medium Priority
?
245 Views
Last Modified: 2010-04-21
500 pts if someone can tell me why the following code gives a segmentation fault in Linux (Redhat Enterprosw WS 3.0) when it runs OK in Unix (Solaris 8).  Less points if you just direct me to a site which eventually answers my question.


struct param_struct {
  char name[hlen];                              /* Parameter name */
  char min[MAX_CATS][PARAM_LEN];                /* Minimum, nominal and maximum values */
  char typ[MAX_CATS][PARAM_LEN];
  char max[MAX_CATS][PARAM_LEN];
  char comment[len];
  struct param_struct *prior;
  struct param_struct *next;
} par_entry;
struct param_struct *parfirst;
struct param_struct *parlast;

int allocate_param (struct param_struct **param, char *name)
{
  short j;

  *param = parfirst;                        /* see if param already exists */
  while (*param) {
    if (!strcmp((*param)->name,name))  return false;      /* Check for param already present */
    *param = (*param)->next;
  }
 
  /***** segmentation fault here in Linux: */
  *param = (struct param_struct *)malloc(sizeof(par_entry));
  if (!(*param)) {
    message ('M',"FATAL ERROR 6: Out of memory in allocating param space.\n",false,3,true);
    exit (25);
  }

  etc.
0
Comment
Question by:jimdgar
  • 5
  • 4
  • 4
13 Comments
 
LVL 40

Expert Comment

by:jlevie
ID: 12488683
What are the definitions of MAX_CATS & PARAM_LEN?
0
 

Author Comment

by:jimdgar
ID: 12488702
#define  MAX_CATS    30
#define  PARAM_LEN  100
0
 
LVL 40

Expert Comment

by:jlevie
ID: 12488994
Oops, I missed a couple of defines... What are hlen and len defined as?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:jimdgar
ID: 12489036
I don't really see the significance unless I'm trying to malloc too much memory, but anyway:

#define  len  256
#define  hlen  128
0
 
LVL 40

Expert Comment

by:jlevie
ID: 12489207
Well, that's what I was wondering, but obviously it isn't a problem unless you are allocating a lot of param_struct's before the failure.

Does this fail on the first call to allocate_param(), or only later in the program's execution?

If it fails on the first call have were the structures initialized before that?

A sample case works for me on RHEL 3.0, but I did ensure that the stuctures were initialized before calling allocate_param().
0
 
LVL 11

Accepted Solution

by:
cjjclifford earned 500 total points
ID: 12491512
out of interest, it looks like there are possibly 2 better ways of finding the end of the list:

1) you have a variable "struct param_struct *parlast;" which would indicate to me you are tracking the end of the list - just add to parlast->next, rather than iterating over the list.
or 2) you are using doubly linked lists, so technically you could link parfirst->prev to parlast, and then use this to add the new parameter...

Compile the application with "gcc -ggdb", and then before running it "ulimit -c unlimited", then with the core file use "gdb" with the executable file as the argument, and then in the GDB prompt "core core.xyz" (where core.xyz is the corefile, usually core.pid). Once there you can look at the stack, etc: in there check the contents of param: "p param" and "*param" - p *param.

What I'd say the problem is the following:

malloc() does not initialize memory when it returns it, so the contents of the structure returned can be anything, in particular "param->next" can be any value. If you are assuming this is NULL initially, and not explicitly setting it to NULL, then it could be the case that the real end of the list actually points to somewhere incorrectly (by param->next containing rubbish value), and the loop keeping going, then it eventually gets to a stage that "param->next" is acually NULL, whereby it tries to assign something (malloc()) to the memory, which in this case is not correct memory, so it shouldn't happen...

incidently, you don't need to cast the return value of malloc(), once you have the correct headers included (stdlib.h).
0
 

Author Comment

by:jimdgar
ID: 12495721
For clarification, I'm using a doubly-linked list and appending new elements to the end. The only initialization I perform during program startup is:
parfirst = NULL;
parlast = NULL;

The remainder of the code (which I left out before) is included below. The segmentation fault occurs at the 1st call to the allocate_param function, altho I use similar structs elsewhere in the program and they've been called before the crash. I'm going to try cjjclifford's suggestion altho it may take me some time as I don't use gdb that often.

struct param_struct {
  char name[hlen];                              /* Parameter name */
  char min[MAX_CATS][PARAM_LEN];                /* Minimum, nominal and maximum values */
  char typ[MAX_CATS][PARAM_LEN];
  char max[MAX_CATS][PARAM_LEN];
  char comment[len];
  struct param_struct *prior;
  struct param_struct *next;
} par_entry;
struct param_struct *parfirst;
struct param_struct *parlast;

int allocate_param (struct param_struct **param, char *name)
{
  short j;

  *param = parfirst;                    /* see if param already exists */
  while (*param) {
    if (!strcmp((*param)->name,name))  return false;
    *param = (*param)->next;
  }
 
  /***** segmentation fault here in Linux: */
  *param = (struct param_struct *)malloc(sizeof(par_entry));
  if (!(*param)) {
    message ('M',"FATAL ERROR 6: Out of memory in allocating param space.\n",false,3,true);
    exit (25);
  }
  strcpy ((*param)->name,name);
  for (j=0; j < MAX_CATS; ++j) {
    strcpy ((*param)->min[j],"");
    strcpy ((*param)->typ[j],"");
    strcpy ((*param)->max[j],"");
  }
  strcpy ((*param)->comment,"");

  if (!parfirst) {
    parfirst = (*param);
    parlast = (*param);
    (*param)->next = NULL;
    (*param)->prior = NULL;
  }
  else {
    (*param)->prior = parlast;
    (*param)->next = NULL;
    parlast->next = (*param);
    parlast = (*param);
  }
  return true;
}                                    /* end of allocate_param */

0
 
LVL 11

Expert Comment

by:cjjclifford
ID: 12495802
what about the code when you are freeing the entries? Since you have a double linked list, it might be the case that one of the two pointers are not being correctly reassigned, so an entry in the list might be incorrectly in there... that said, you did say this was not problematic on SunOS, so this scenario would really have been seen there too....

Does it dump the first time through, or after several iterations?
0
 
LVL 11

Expert Comment

by:cjjclifford
ID: 12495844
sorry you just said 1st, I missed that...

0
 
LVL 11

Expert Comment

by:cjjclifford
ID: 12495932
Definitely have a look with GDB, very simple to do, or at least, the bits I asked for anyway :-)

One thing I noted above - don't cast the return value of malloc(): it returns "void*" which will become the type it is assigned to. casting this actually hides compile-time warnings, and could be hiding problems...
You only require the correct standard libraries included (<stdlib.h> I believe!)

With the "*param" replaced with a local variable, the malloc() code looks fine....

/*********** replaced with local var **************/
 struct param_struct *elem;

 elem = parfirst;                    /* see if param already exists */
  while (elem) {
    if (!strcmp(elem->name,name))  return false;
    elem = elem->next;
  }
 
  // NOTE
  // NOTE I've removed the unnecessary cast (that actually can hide compile problems!!!!)
  //  NOTE Also, I've used the same type as the type of the var, for clarity...
  elem = malloc(sizeof(struct param_struct));
  if (!elem) {
    message ('M',"FATAL ERROR 6: Out of memory in allocating param space.\n",false,3,true);
    exit (25);
  }
  strcpy (elem->name,name);
  for (j=0; j < MAX_CATS; ++j) {
    strcpy (elem->min[j],"");
    strcpy (elem->typ[j],"");
    strcpy (elem->max[j],"");
  }
  strcpy (elem->comment,"");

  if (!parfirst) {
    parfirst = elem;
    parlast = elem;
    elem->next = NULL;
    elem->prior = NULL;
  }
  else {
    elem->prior = parlast;
    elem->next = NULL;
    parlast->next = elem;
    parlast = elem;
  }
  // Now just assign for returning
  *param = elem;
  return true;
0
 
LVL 40

Expert Comment

by:jlevie
ID: 12496413
If you set parfirst = NULL; it should fail on the first call since you'll be attempting to dereference a null pointer from:

  *param = parfirst;                    /* see if param already exists */
  while (*param) {
    if (!strcmp((*param)->name,name))  return false;
 
0
 
LVL 11

Expert Comment

by:cjjclifford
ID: 12496460
jlevie, nope, "param" is a "struct param_struct **", so dereferencing param gives a holder for a pointer, which is what he assigns to *param - its easier to read with the code sample above with a local variable used in place of the double pointer...
0
 

Author Comment

by:jimdgar
ID: 12589737
OK, finally solved it. I had a function declared as int which did not have a default return value at the end of the function. Even tho I use gcc on both Solaris & Linux, the Solaris version of my sw apparently defaults to a return value while the Linux version did not. Hence the segmentation fault (which incidentally moved around).

Pts to cjjclifford as the suggestion to use gdb led me to the bug.

jimdgar
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever been frustrated by having to click seven times in order to retrieve a small bit of information from the web, always the same seven clicks, scrolling down and down until you reach your target? When you know the benefits of the command l…
The purpose of this article is to demonstrate how we can upgrade Python from version 2.7.6 to Python 2.7.10 on the Linux Mint operating system. I am using an Oracle Virtual Box where I have installed Linux Mint operating system version 17.2. Once yo…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Please read the paragraph below before following the instructions in the video — there are important caveats in the paragraph that I did not mention in the video. If your PaperPort 12 or PaperPort 14 is failing to start, or crashing, or hanging, …
Suggested Courses

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question