i have test case keeps throwing segmentation fault. when used gdb try , find segfaulting, found failed in call free() in code being tested.
now thing is, parameter being passed free() allocated using malloc() , wasn't adjusted after (afaict).
here's relevant code:
structure.h:
#pragma once //=== includes #include <stdint.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include "kv/backend.h" #include "xm.h" #include "constants.h" //=== defines #define structure_type_null (0x00) // invalid - should never see #define structure_type_sub (0x01) // substructure #define structure_type_i64 (0x02) // 64b signed integer #define structure_type_u64 (0x03) // 64b unsigned integer #define structure_type_h64 (0x04) // 64b translate hex (ie: 0x'...') #define structure_type_f64 (0x05) // 64b ieee 754 double float #define structure_type_blob (0x06) // variable length binary blob #define structure_type_string (0x07) // variable length null terminated string #define structure_type_time (0x08) // 64b packed ymdhms time #define structure_type_unixtime (0x09) // 64b signed unix time //=== structures typedef struct { int64_t year :35; uint64_t month :4; uint64_t day :5; uint64_t hour :5; uint64_t minute :6; uint64_t second :6; } structure_time; typedef struct structure_struct { uint8_t *key; union { int64_t i64; uint64_t u64; uint64_t h64; double f64; uint8_t *blob; uint8_t *string; structure_time time; int64_t unixtime; struct structure_struct *children; }; union { uint16_t len; // blob + string (includes null terminator) uint16_t count; // children }; uint8_t type; } structure; //=== special static inline int cmp_structure (const void *arg1, const void *arg2) { const structure *a = arg1; const structure *b = arg2; return strcmp (a->key, b->key); // compare keys } #define sort_name structure #define sort_type structure #define sort_cmp(x, y) cmp_structure (&x, &y) #include "../deps/sort/sort.h" //=== functions static inline void structuresortchildren (structure *s) { structure_tim_sort (s->children, s->count); return; } int structureaddchildren (structure *parent, const structure *children, int count); void structurefree (structure *s); structure.c:
#include "structure.h" int structureaddchildren (structure *parent, const structure *children, int count) { if (parent->type != structure_type_sub) return 1; // yeah lets not cause memory issue // realloc () may lose data structure *tmp = malloc ((parent->count + count) * sizeof (structure *)); if (!tmp) return -1; // memory failure // copy on old children memcpy (tmp, parent->children, parent->count * sizeof (structure)); if (parent->count > 0) free (parent->children); // segfault occurs here parent->children = tmp; // copy on new children memcpy (&parent->children[parent->count], children, count * sizeof (structure)); parent->count += count; // resort array allow bsearch() find members structure_tim_sort (parent->children, parent->count); return 0; } test_structure.c:
#include "test.h" #include "../structure.h" const char *key[4] = { "head", "number", "integer", "string" }; const char *text = "text"; void printstructure (const structure *s) { switch (s->type) { case structure_type_sub: { printf ("structure:\n" \ "\ttype:\t%s\n" \ "\tkey:\t%s\n" \ "\tnumber count:\t%i\n\n", "(sub)structure", s->key, s->count); break; } case structure_type_string: { // assert (s->len == (strlen (s->string) + 1)); // null terminator printf ("structure:\n" \ "\ttype:\t%s\n" \ "\tkey:\t%s\n" \ "\tvalue:\t%s\n" \ "\tlength:\t%i\n\n", "string", s->key, s->string, s->len); break; } case structure_type_i64: { printf ("structure:\n" \ "\ttype:\t%s\n" \ "\tkey:\t%s\n" \ "\tvalue:\t%i\n\n", "64-bit signed integer", s->key, (int) s->i64); break; } case structure_type_f64: { printf ("structure:\n" \ "\ttype:\t%s\n" \ "\tkey:\t%s\n" \ "\tvalue:\t%f\n\n", "64-bit fp number", s->key, (float) s->f64); break; } } return; } void test (void) { structure *head, *number, *integer, *string; // basic allocations head = malloc (sizeof (structure)); head->key = strdup (key[0]); head->type = structure_type_sub; head->count = 0; number = malloc (sizeof (structure)); number->key = strdup (key[1]); number->type = structure_type_f64; number->f64 = 3.1415; integer = malloc (sizeof (structure)); integer->key = strdup (key[2]); integer->type = structure_type_i64; integer->i64 = -42; string = malloc (sizeof (structure)); string->key = strdup (key[3]); string->type = structure_type_string; string->string = strdup (text); string->len = strlen (text) + 1; // null terminator // lets see current states printf ("\n---structures built---\n\n"); printstructure (head); printstructure (number); printstructure (integer); printstructure (string); // lets put them // head +> number // -> integer // -> string structureaddchildren (head, integer, 1); structureaddchildren (head, string, 1); structureaddchildren (head, number, 1); // segfault occurs on call ... } int main (int argc, char *argv) { test (); return 0; } now, segfault occurs on third invocation of structureaddchildren(). specifically, on line
structureaddchildren (head, number, 1); // segfault occurs on call
from test_structure.c, once structureaddchildren called, segfault occurs on line
free (parent->children); // segfault occurs here
from structure.c.
i can't imagine causing segfault, since structureaddchildren() point @ memory being allocated , nothing else messes pointer (writing it).
so, overall, causing segfault , how can resolve it?
when allocating memory new (and old) structures in structureaddchildren(), you've calculated new size using sizeof(structure *) when should sizeof(structure). result, insufficient space allocated , later writes overrun allocated space. corrected line should be:
structure *tmp = malloc ((parent->count + count) * sizeof (structure));
Comments
Post a Comment