KevinA
KevinA

Reputation: 629

Bus Error only when running on Solarix Unix Box

It compiles up and runs on my Linux box(Ubuntu) as well as other linux boxes both x86 and x64 but on a SunOS Generic_142900-02 sun4u sparc unix box, it crashes on the line

matrix->col_head[i] = col_h;

with a bus error, Also, when i compile it up with GCC -G, GDB fails to find any debuging symbols

Here is the Code:

typedef unsigned short short_u;
typedef struct node{
  short_u         row;
  short_u         col;
  int             value;
  struct node*    row_l;
  struct node*    col_l;
}node_t;

typedef struct matrix{
  short_u     N;
  node_t**    row_head;
  node_t**    col_head;
}matrix_t;

matrix_t* init_matrix(int N){
  matrix_t* matrix = malloc(sizeof(matrix_t*));
  matrix->row_head = malloc(sizeof(node_t*)*N);
  matrix->col_head = malloc(sizeof(node_t*)*N);
  matrix->N = N;
  for (int i = 0; i < N; i++){
      /* row */
      node_t* row_h = malloc(sizeof(node_t*));
      row_h->col = 0;
      row_h->row = i+1;
      row_h->value = 0;
      row_h->col_l = row_h;
      if (i != 0)
          matrix->row_head[i-1]->row_l = row_h;
      matrix->row_head[i] = row_h;
      /* col */
      node_t* col_h = malloc(sizeof(node_t*));
      col_h->col = i+1;
      col_h->row = 0;
      col_h->value = 0;
      col_h->row_l = col_h;
      if (i != 0)
          matrix->col_head[i-1]->col_l = col_h;
      matrix->col_head[i] = col_h;
  }
  matrix->row_head[N-1]->row_l = matrix->row_head[0];
  matrix->col_head[N-1]->col_l = matrix->col_head[0];

  return matrix;
}

Upvotes: 0

Views: 131

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 754530

Your code does not run cleanly under valgrind on Mac OS X.

I wrapped it into a complete program thus:

#include <stdlib.h>
#include <stdio.h>

typedef unsigned short short_u;
typedef struct node{
  short_u         row;
  short_u         col;
  int             value;
  struct node*    row_l;
  struct node*    col_l;
}node_t;

typedef struct matrix{
  short_u     N;
  node_t**    row_head;
  node_t**    col_head;
}matrix_t;

static matrix_t* init_matrix(int N){
  matrix_t* matrix = malloc(sizeof(matrix_t*));
  matrix->row_head = malloc(sizeof(node_t*)*N);
  matrix->col_head = malloc(sizeof(node_t*)*N);
  matrix->N = N;
  for (int i = 0; i < N; i++){
      /* row */
      node_t* row_h = malloc(sizeof(node_t*));
      row_h->col = 0;
      row_h->row = i+1;
      row_h->value = 0;
      row_h->col_l = row_h;
      if (i != 0)
          matrix->row_head[i-1]->row_l = row_h;
      matrix->row_head[i] = row_h;
      /* col */
      node_t* col_h = malloc(sizeof(node_t*));
      col_h->col = i+1;
      col_h->row = 0;
      col_h->value = 0;
      col_h->row_l = col_h;
      if (i != 0)
          matrix->col_head[i-1]->col_l = col_h;
      matrix->col_head[i] = col_h;
  }
  matrix->row_head[N-1]->row_l = matrix->row_head[0];
  matrix->col_head[N-1]->col_l = matrix->col_head[0];

  return matrix;
}

#if 0
static void free_matrix(matrix_t *matrix)
{
    for (int i = 0; i < matrix->N; i++)
    {
        free(matrix->row_head[i]);
        free(matrix->col_head[i]);
    }
    free(matrix->row_head);
    free(matrix->col_head);
    free(matrix);
}
#endif /* 0 */

int main(void)
{
    matrix_t *m = init_matrix(100);
    //free_matrix(m);
    return(0);
}

It compiles cleanly. It runs without actually crashing on Mac OS X 10.7.3.

Output from valgrind

However, valgrind complains like this (I called the program xx, and the source was xx.c):

==73807== Memcheck, a memory error detector
==73807== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==73807== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==73807== Command: ./xx
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000D11: init_matrix (xx.c:21)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005128 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000D2F: init_matrix (xx.c:22)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005130 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000D8A: init_matrix (xx.c:30)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005840 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000D5A: init_matrix (xx.c:26)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000DB7: init_matrix (xx.c:33)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005128 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000E0A: init_matrix (xx.c:39)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005888 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000DDA: init_matrix (xx.c:35)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000E37: init_matrix (xx.c:42)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005130 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000D9A: init_matrix (xx.c:32)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005128 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000DAF: init_matrix (xx.c:32)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005838 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000D5A: init_matrix (xx.c:26)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000E1A: init_matrix (xx.c:41)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005130 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000E2F: init_matrix (xx.c:41)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005890 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000DDA: init_matrix (xx.c:35)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000E64: init_matrix (xx.c:44)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005128 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000E79: init_matrix (xx.c:44)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005128 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000E80: init_matrix (xx.c:44)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100009618 is 0 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000D5A: init_matrix (xx.c:26)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000E88: init_matrix (xx.c:45)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005130 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid read of size 8
==73807==    at 0x100000E9D: init_matrix (xx.c:45)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100005130 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000CF2: init_matrix (xx.c:20)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== Invalid write of size 8
==73807==    at 0x100000EA4: init_matrix (xx.c:45)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807==  Address 0x100009670 is 8 bytes after a block of size 8 alloc'd
==73807==    at 0xB823: malloc (vg_replace_malloc.c:266)
==73807==    by 0x100000DDA: init_matrix (xx.c:35)
==73807==    by 0x100000EE3: main (xx.c:66)
==73807== 
==73807== 
==73807== HEAP SUMMARY:
==73807==     in use at exit: 5,303 bytes in 235 blocks
==73807==   total heap usage: 235 allocs, 0 frees, 5,303 bytes allocated
==73807== 
==73807== LEAK SUMMARY:
==73807==    definitely lost: 1,608 bytes in 3 blocks
==73807==    indirectly lost: 1,600 bytes in 200 blocks
==73807==      possibly lost: 0 bytes in 0 blocks
==73807==    still reachable: 2,095 bytes in 32 blocks
==73807==         suppressed: 0 bytes in 0 blocks
==73807== Rerun with --leak-check=full to see details of leaked memory
==73807== 
==73807== For counts of detected and suppressed errors, rerun with: -v
==73807== ERROR SUMMARY: 804 errors from 16 contexts (suppressed: 1 from 1)

When I enabled the free_matrix() function, I got a few more errors, but I believe they were consequences of the problems in init_matrix(). I then didn't get any leaked memory (the 'still reachable' memory is in the system libraries; all runs of valgrind have a noticeable amount of such memory on Mac OS X).

Amended Code

The diagnosis by George Skoptsov in his answer is spot-on. This fixed code, with the free_matrix() enabled, works without error under valgrind. Note the use of the idioms:

SomeType *variable = malloc(sizeof(*variable));
SomeType *arrayvar = malloc(sizeof(*arrayvar) * N);

Although a little uncomfortable at first, these avoid the problem you ran into. I'm trying to remember to use them; I'm still relearning the techniques first learned long enough ago that I'm suffering from a dose of "it is hard to teach old dogs new tricks".

#include <stdlib.h>
#include <stdio.h>

typedef unsigned short short_u;
typedef struct node{
  short_u         row;
  short_u         col;
  int             value;
  struct node*    row_l;
  struct node*    col_l;
}node_t;

typedef struct matrix{
  short_u     N;
  node_t**    row_head;
  node_t**    col_head;
}matrix_t;

static matrix_t* init_matrix(int N){
  matrix_t* matrix = malloc(sizeof(*matrix));
  matrix->row_head = malloc(sizeof(*matrix->row_head)*N);
  matrix->col_head = malloc(sizeof(*matrix->col_head)*N);
  matrix->N = N;
  for (int i = 0; i < N; i++){
      /* row */
      node_t* row_h = malloc(sizeof(*row_h));
      row_h->col = 0;
      row_h->row = i+1;
      row_h->value = 0;
      row_h->col_l = row_h;
      if (i != 0)
          matrix->row_head[i-1]->row_l = row_h;
      matrix->row_head[i] = row_h;
      /* col */
      node_t* col_h = malloc(sizeof(*col_h));
      col_h->col = i+1;
      col_h->row = 0;
      col_h->value = 0;
      col_h->row_l = col_h;
      if (i != 0)
          matrix->col_head[i-1]->col_l = col_h;
      matrix->col_head[i] = col_h;
  }
  matrix->row_head[N-1]->row_l = matrix->row_head[0];
  matrix->col_head[N-1]->col_l = matrix->col_head[0];

  return matrix;
}

static void free_matrix(matrix_t *matrix)
{
    for (int i = 0; i < matrix->N; i++)
    {
        free(matrix->row_head[i]);
        free(matrix->col_head[i]);
    }
    free(matrix->row_head);
    free(matrix->col_head);
    free(matrix);
}

int main(void)
{
    matrix_t *m = init_matrix(100);
    free_matrix(m);
    return(0);
}

There are five places where malloc() is called; there are also five places where free() is called. And two of the five allocations and frees are in 0..N-1 loops, which all balances nicely.

Revised output from valgrind

==73943== Memcheck, a memory error detector
==73943== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==73943== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==73943== Command: ./xx
==73943== 
==73943== 
==73943== HEAP SUMMARY:
==73943==     in use at exit: 2,095 bytes in 32 blocks
==73943==   total heap usage: 235 allocs, 203 frees, 8,519 bytes allocated
==73943== 
==73943== LEAK SUMMARY:
==73943==    definitely lost: 0 bytes in 0 blocks
==73943==    indirectly lost: 0 bytes in 0 blocks
==73943==      possibly lost: 0 bytes in 0 blocks
==73943==    still reachable: 2,095 bytes in 32 blocks
==73943==         suppressed: 0 bytes in 0 blocks
==73943== Rerun with --leak-check=full to see details of leaked memory
==73943== 
==73943== For counts of detected and suppressed errors, rerun with: -v
==73943== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)

Lessons to learn

So, there are various lessons to learn from this brief story:

  1. Be grateful the Sun pointed out the problem to you.
  2. Learn how to use valgrind.
  3. Consider using the Type *pointer = malloc(sizeof(*pointer)); idiom for allocations.

Upvotes: 1

George Skoptsov
George Skoptsov

Reputation: 3971

When you do

matrix_t* matrix = malloc(sizeof(matrix_t*));

you allocate space of a pointer to a matrix_t, which is not enough for the entire matrix_t. Your bus error is probably the result of accessing unallocated memory at matrix->row_head and matrix->col_head.

You repeat this mistake in lines

  node_t* row_h = malloc(sizeof(node_t*));

and

  node_t* col_h = malloc(sizeof(node_t*));

The fact that you don't get a segfault on the Linux machines is a happy accident.

Upvotes: 2

Related Questions