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

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.
jimdgarAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jlevieCommented:
What are the definitions of MAX_CATS & PARAM_LEN?
0
jimdgarAuthor Commented:
#define  MAX_CATS    30
#define  PARAM_LEN  100
0
jlevieCommented:
Oops, I missed a couple of defines... What are hlen and len defined as?
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

jimdgarAuthor Commented:
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
jlevieCommented:
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
cjjcliffordCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
jimdgarAuthor Commented:
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
cjjcliffordCommented:
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
cjjcliffordCommented:
sorry you just said 1st, I missed that...

0
cjjcliffordCommented:
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
jlevieCommented:
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
cjjcliffordCommented:
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
jimdgarAuthor Commented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Linux OS Dev

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.