pike.git / src / stralloc.c

version» Context lines:

pike.git/src/stralloc.c:38:      // starting hilfe creates 6128 strings.   #define BEGIN_HASH_SIZE 16384      static unsigned int hash_prefix_len=64;   static unsigned int need_more_hash_prefix_depth=0;   static unsigned int need_new_hashkey_depth=0;      static size_t hashkey = 0;    - struct hentry { -  size_t hval; -  struct pike_string *str; - }; -  +    static struct { -  struct hentry *table; +  struct pike_string **__restrict__ table;    size_t size;    size_t limit; /* size * 0.8, aproximately. */    size_t num_strings;    size_t mask;   } string_hash;      PMOD_EXPORT struct pike_string *empty_pike_string = 0;      /*** Main string hash function ***/   
pike.git/src/stralloc.c:412:      static void locate_problem(int (*isproblem)(const struct pike_string *))   {    unsigned INT32 e;    struct pike_string *s;    DM(struct memhdr *yes=alloc_memhdr());    DM(struct memhdr *no=alloc_memhdr());       for(e=0;e<string_hash.size;e++)    { -  if( (s = string_table.table[e].str) ) +  if( (s = string_table.table[e]) )    {    if(isproblem(s))    {    fprintf(stderr,"***Guilty string:\n");    debug_dump_pike_string(s, 70);    DM(add_marks_to_memhdr(yes,s));    }else{    DM(add_marks_to_memhdr(no,s));    }    }
pike.git/src/stralloc.c:466:    ptrdiff_t len,    int size_shift,    size_t hval)   {    size_t h=HMODULO(hval);    size_t dist=0;       for(;;)    {    struct pike_string *probe; -  if(!(probe=string_hash.table[h].str)) +  if(!(probe=string_hash.table[h]))    return NULL; -  if(dist > probe_dist(string_hash.table[h].hval,h)) -  return NULL; +     -  if(string_hash.table[h].hval == hval) -  { -  if( len == probe->len && -  size_shift == probe->size_shift && -  (s == probe->str || -  !memcmp(s,probe->str,len<<size_shift))) -  { +  if(size_shift == probe->size_shift +  && len == probe->len +  && !memcmp(s,probe->str,len<<size_shift))    return probe; -  } -  } +  +  if(dist > probe_dist(string_hash.table[h]->hval,h)) +  return NULL;    dist++;    h = HMODULO(h+1);    }    return 0; /* not found */   }      struct pike_string *binary_findstring(const char *foo, ptrdiff_t l)   {    return internal_findstring(foo, l, 0, low_do_hash(foo,l,0));   }
pike.git/src/stralloc.c:535:    if( tmp )    free( tmp );    return res;   }      struct pike_string *findstring(const char *foo)   {    return binary_findstring(foo, strlen(foo));   }    - static void low_link_pike_string( struct hentry entry ); + static void low_link_pike_string( struct pike_string *entry );    - static void stralloc_rehash(void) + static void stralloc_grow(void)   {    size_t old,h; -  struct hentry *old_table; +  struct pike_string **old_table;       old=string_hash.size;    old_table=string_hash.table;    if( !string_hash.size )    string_hash.size = BEGIN_HASH_SIZE;    else    string_hash.size *= 2;       string_hash.limit = (size_t)((double)string_hash.size*0.8); -  string_hash.table = xcalloc(sizeof(struct hentry), string_hash.size); +  string_hash.table = xcalloc(sizeof(struct pike_string**), string_hash.size);    string_hash.mask = string_hash.size-1;   /* fprintf( stderr, "stralloc rehash: sz=%d, mask=0x%8x, limit=%d, num=%d\n", */   /* string_hash.size, string_hash.mask,string_hash.limit,string_hash.num_strings); */       for(h=0;h<old;h++) -  if(old_table[h].str) +  if(old_table[h])    low_link_pike_string(old_table[h]);       free(old_table);   }    -  + static void stralloc_rehash() + { +  /* rehash without resize, but new hvals for all strings. */ +  size_t h; +  struct pike_string **ht = string_hash.table; +  string_hash.table = malloc( sizeof(struct pike_string*) * string_hash.size ); +  for(h=0;h<string_hash.size;h++) +  { +  struct pike_string *tmp=ht[h]; +  if( !tmp ) +  continue; +  /* rehash needed, since algorithm changed */ +  tmp->hval = do_hash(tmp); +  low_link_pike_string( tmp ); +  } +  free(ht); + } +    /* Allocation of strings */      #define STRING_BLOCK 4096   static struct block_allocator string_allocator = BA_INIT(sizeof(struct pike_string), STRING_BLOCK);      static void free_unlinked_pike_string(struct pike_string * s) {    switch (s->flags & STRING_ALLOC_MASK)    {    case STRING_ALLOC_MALLOC:    free(s->str);
pike.git/src/stralloc.c:589:      /* note that begin_shared_string expects the _exact_ size of the string,    * not the maximum size    */   PMOD_EXPORT struct pike_string *debug_begin_shared_string(size_t len)   {    return debug_begin_wide_shared_string(len, 0);   }      /* Insert a new strings. Note: Guaranteed to be new */ - static void low_link_pike_string( struct hentry cur ) + static void low_link_pike_string( struct pike_string *str )   { -  size_t h = HMODULO(cur.hval); +  size_t hval = str->hval; +  size_t h = HMODULO(hval);    size_t dist = 0;    size_t max_run = 0, length_issue=0;       for(;;)    {    size_t existing_dist; -  if( string_hash.table[h].str == 0 ) +  if( LIKELY(!string_hash.table[h]) )    {    /* empty slot. */ -  string_hash.table[h] = cur; +  string_hash.table[h] = str;    return;    }    -  existing_dist = probe_dist(string_hash.table[h].hval, h); +  existing_dist = probe_dist(string_hash.table[h]->hval, h);    -  /* This code is for the rehash heuristics. */ -  if( string_hash.table[h].hval == cur.hval ) +  +  /* ----- This code is for the rehash heuristics. */ +  if( string_hash.table[h]->hval == hval )    {    max_run++; -  if( cur.str->len > hash_prefix_len+8 ) +  if( str->len > hash_prefix_len+8 )    length_issue++;    }    else    {    if( length_issue )    need_more_hash_prefix_depth=MAXIMUM(max_run,need_more_hash_prefix_depth);    else    need_new_hashkey_depth=MAXIMUM(max_run,need_new_hashkey_depth);    max_run=0;    length_issue=0;    } -  /* end heuristics. */ +  /* ----- end heuristics. */       if( existing_dist < dist )    { -  struct hentry tmp = string_hash.table[h]; +  struct pike_string *tmp = string_hash.table[h];    /* steal slot, then insert stolen one. */ -  string_hash.table[h] = cur; -  cur = tmp; +  string_hash.table[h] = str; +  str = tmp;    dist = existing_dist; - /* max_run=0; */ - /* length_issue=0; */ +  /* inentionally not reassigning hval. the max-run length +  * heuristics are only for the "primary" string. +  */    } -  +     h = HMODULO(h + 1);    dist++;    }   }    - static struct hentry make_hentry(size_t hval, struct pike_string *s ) + static void link_pike_string(struct pike_string *s)   { -  struct hentry tmp; -  tmp.hval = hval; -  tmp.str = s; -  return tmp; - } -  - static void link_pike_string(struct pike_string *s, size_t hval) - { -  size_t h; -  +    #ifdef PIKE_DEBUG    if (!(s->flags & STRING_NOT_SHARED)) {    debug_dump_pike_string(s, 70);    Pike_fatal("String already linked.\n");    }       if (PIKE_MEM_NOT_DEF_RANGE (s->str, (s->len + 1) << s->size_shift))    Pike_fatal ("Got undefined contents in pike string %p.\n", s);   #endif -  +     s->flags &= ~STRING_NOT_SHARED; -  if(++string_hash.num_strings > string_hash.limit) -  stralloc_rehash(); +     -  low_link_pike_string( make_hentry(hval,s) ); +  if(UNLIKELY(++string_hash.num_strings > string_hash.limit)) +  stralloc_grow();    -  +  low_link_pike_string( s ); +     /* These heuristics might require tuning! /Hubbe */ -  if((need_more_hash_prefix_depth > 8) || -  (need_new_hashkey_depth > 32)) +  if(UNLIKELY((need_more_hash_prefix_depth > 8) || +  (need_new_hashkey_depth > 32)))    { -  /* Changed heuristic 2005-01-17: -  * -  * Increase hash_prefix_len if there's some bucket containing -  * more than 4 strings that are longer -  * than hash_prefix_len. -  * /grubba -  * -  * Changed heuristic 2011-12-30: -  * -  * Generate a new hash key if there's some bucket containing -  * more than 16 strings. This ought to -  * suffice to alleviate the #hashdos vulnerability. -  * -  * /grubba -  */ -  -  /* This could in theory have a pretty ugly complexity -  * /Hubbe -  */ -  +     if (need_new_hashkey_depth > 32) {    /* A simple mixing function. */    hashkey ^= (hashkey << 5) ^ (current_time.tv_sec ^ current_time.tv_usec);    need_new_hashkey_depth = 0;    } -  +     if (need_more_hash_prefix_depth > 8)    {    hash_prefix_len=hash_prefix_len*2;    need_more_hash_prefix_depth=0;    } -  -  /* This could be done without allocating and freeing the whole table. -  But doing so is a .. tad .. more complex with this implementation. -  -  I guess the question is: is it needed? -  */ -  struct hentry *ht = string_hash.table; -  string_hash.table = malloc( sizeof(struct hentry) * string_hash.size ); -  for(h=0;h<string_hash.size;h++) -  { -  struct hentry *tmp=ht+h; -  if( !tmp->str ) -  continue; -  /* rehash needed, since algorithm changed */ -  low_link_pike_string( make_hentry(do_hash(tmp->str),tmp->str) ); +  stralloc_rehash();    } -  free(ht); +    } - } +       PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, int shift)   {    struct pike_string *t = NULL;    size_t bytes = (len+1) << shift;   #ifdef PIKE_DEBUG    extern int d_flag;    if(d_flag>10)    verify_shared_strings_tables();   #endif
pike.git/src/stralloc.c:789:   PMOD_EXPORT struct pike_string * make_shared_static_string(const char *str, size_t len,    enum size_shift shift)   {    struct pike_string *s;    ptrdiff_t h = low_do_hash(str, len,0);       s = internal_findstring(str,len,shift,h);       if (!s) {    s = make_static_string(str, len, shift); -  link_pike_string(s, h); +  s->hval = do_hash(s); +  link_pike_string(s);    } else {       if (!string_is_static(s)) {    if (string_is_block_allocated(s)) {    ba_free(&string_allocator, s->str);    } else {    free(s->str);    }    s->flags &= ~STRING_ALLOC_MASK;    s->flags |= STRING_ALLOC_STATIC;
pike.git/src/stralloc.c:845: Inside #if defined(PIKE_DEBUG)
   break;    }       default:    Pike_fatal("ARGHEL! size_shift:%d\n", s->size_shift);    }    }   #endif       len = s->len; -  h = do_hash(s); -  s2 = internal_findstring(s->str, len, s->size_shift, h); +  s->hval = do_hash(s); +  s2 = internal_findstring(s->str, len, s->size_shift, s->hval);   #ifdef PIKE_DEBUG    if(s2==s)    Pike_fatal("end_shared_string called twice! (or something like that)\n");   #endif       if(s2)    {    free_string(s);    s = s2;    add_ref(s);    }else{ -  link_pike_string(s, h); +  link_pike_string(s);    }       return s;   }      /*    * This function checks if the shift size can be decreased before    * entering the string in the shared string table    */   PMOD_EXPORT struct pike_string *end_shared_string(struct pike_string *s)
pike.git/src/stralloc.c:931:    tmp = make_shared_binary_pcharp(MKPCHARP_STR(str),len);    free_string(str);    return tmp;   }         PMOD_EXPORT struct pike_string * debug_make_shared_binary_string(const char *str,size_t len)   {    ptrdiff_t h;    struct pike_string *s; + #if 0    if( !len )    {    empty_pike_string->refs++;    return empty_pike_string;    } -  + #endif    h = low_do_hash(str, len,0);    s = internal_findstring(str,len,0,h);    if (!s)    {    s=begin_shared_string(len);    memcpy(s->str, str, len); -  link_pike_string(s, h); +  s->hval = h; +  link_pike_string(s);    } else {    add_ref(s);    }       return s;   }      PMOD_EXPORT struct pike_string * debug_make_shared_binary_pcharp(const PCHARP str,size_t len)   {    if( !len )
pike.git/src/stralloc.c:1004:    return end_shared_string(s);    }       h=low_do_hash(str, len, 1);       s = internal_findstring((char *)str,len,1,h);    if (!s)    {    s=begin_wide_shared_string(len,1);    memcpy(s->str, str, len<<1); -  link_pike_string(s, h); +  s->hval = h; +  link_pike_string(s);    } else {    add_ref(s);    }       return s;   }      PMOD_EXPORT struct pike_string * debug_make_shared_binary_string2(const p_wchar2 *str,size_t len)   {    struct pike_string *s;
pike.git/src/stralloc.c:1039:    return end_shared_string(s); /* not entirely optimal */    }       h=low_do_hash(str, len, 2);       s = internal_findstring((char *)str,len,2,h);    if (!s)    {    s=begin_wide_shared_string(len,2);    memcpy(s->str, str, len<<2); -  link_pike_string(s, h); +  s->hval = h; +  link_pike_string(s);    } else {    add_ref(s);    }    return s;   }      PMOD_EXPORT struct pike_string *debug_make_shared_string(const char *str)   {    return make_shared_binary_string(str, strlen(str));   }
pike.git/src/stralloc.c:1072:      PMOD_EXPORT struct pike_string *debug_make_shared_string2(const p_wchar2 *str)   {    INT32 len;    for(len=0;str[len];len++);    return debug_make_shared_binary_string2(str,len);   }      /*** Free strings ***/    - static void unlink_pike_string(struct pike_string *s,size_t hval) + static void unlink_pike_string(struct pike_string *s)   { -  size_t h = HMODULO(hval); +  size_t h = HMODULO(s->hval); + #ifdef PIKE_DEBUG    size_t dist = 0; -  + #endif    string_hash.num_strings--;    s->flags |= STRING_NOT_SHARED;       for(;;)    { -  if(string_hash.table[h].str == s) +  if(string_hash.table[h] == s)    {    size_t end = HMODULO(h+1);    /* Found entry. Now maintain invariant. */    for(;;)    { -  if(!string_hash.table[end].str || -  !probe_dist(string_hash.table[end].hval,end)) +  if(!string_hash.table[end] || +  !probe_dist(string_hash.table[end]->hval,end))    { -  string_hash.table[h].str = NULL; +  string_hash.table[h] = NULL;    return;    }    string_hash.table[h] = string_hash.table[end];    h = end;    end = HMODULO(end+1);    }    } -  if(!string_hash.table[h].str || -  (dist > probe_dist(string_hash.table[h].hval,h))) + #ifdef PIKE_DEBUG +  if(!string_hash.table[h] || +  (dist > probe_dist(string_hash.table[h]->hval,h)))    Pike_fatal( "Failed to find string to unlink in table!\n");    dist++; -  + #endif    h = HMODULO(h+1);    }   }      PMOD_EXPORT void do_free_string(struct pike_string *s)   {    if (s)    free_string(s);   }   
pike.git/src/stralloc.c:1135: Inside #if defined(PIKE_DEBUG)
   describe_something(s, T_STRING, 0,2,0, NULL);   #endif    Pike_fatal("Freeing string with %d references.\n", s->refs);    }    if (s->size_shift > 2) {    Pike_fatal("Freeing string with bad shift (0x%08x); could it be a type?\n",    s->size_shift);    }   #endif    if (!(s->flags & STRING_NOT_SHARED)) -  unlink_pike_string(s,do_hash(s)); +  unlink_pike_string(s);    if (s->flags & STRING_CLEAR_ON_EXIT)    guaranteed_memset(s->str, 0, s->len<<s->size_shift);    free_unlinked_pike_string(s);    GC_FREE_SIMPLE_BLOCK(s);   }      void do_really_free_string(struct pike_string *s)   {    if (s)    really_free_string(s);
pike.git/src/stralloc.c:1174:    {    long alloced_strings[8] = {0,0,0,0,0,0,0,0};    long alloced_bytes[8] = {0,0,0,0,0,0,0,0};    long num_distinct_strings[8] = {0,0,0,0,0,0,0,0};    long bytes_distinct_strings[8] = {0,0,0,0,0,0,0,0};    long overhead_bytes[8] = {0,0,0,0,0,0,0,0};    unsigned INT32 e;    struct pike_string *p;    for(e=0;e<string_hash.size;e++)    { -  if( (p = string_hash.table[e].str) ) +  if( (p = string_hash.table[e]) )    {    int key = p->size_shift;    num_distinct_strings[key]++;    alloced_bytes[key] += p->refs*sizeof(struct pike_string);    alloced_strings[key] += p->refs;    if (string_is_block_allocated(p)) {    alloced_bytes[key] +=    p->refs*sizeof(struct pike_string);    } else {    alloced_bytes[key] +=
pike.git/src/stralloc.c:1318: Inside #if defined(PIKE_DEBUG)
     PMOD_EXPORT void verify_shared_strings_tables(void)   {    unsigned INT32 e, h, num=0;    struct pike_string *s;       last_stralloc_verify=current_do_debug_cycle;       for(e=0;e<string_hash.size;e++)    { -  size_t hval = string_hash.table[e].hval; -  struct pike_string *str = string_hash.table[e].str; +  struct pike_string *str = string_hash.table[e];    if(!str)    continue;    num++;       if (bad_pointer(s)) {    Pike_fatal("Odd string pointer in string table!\n");    }       if(s->len < 0)    Pike_fatal("Shared string shorter than zero bytes.\n");
pike.git/src/stralloc.c:1342: Inside #if defined(PIKE_DEBUG)
   {    locate_problem(has_zero_refs);    Pike_fatal("Shared string had too few references.\n");    }       if(index_shared_string(s,s->len))    {    locate_problem(improper_zero_termination);    Pike_fatal("Shared string didn't end with a zero.\n");    } -  if(do_hash(s) != hval) +  if(do_hash(s) != s->hval)    {    Pike_fatal("Illegal hash for string.\n");    }    }    if(num != string_hash.num_strings)    Pike_fatal("Num strings is wrong %d!=%d\n",num,string_hash.num_strings);   }      int safe_debug_findstring(struct pike_string *foo)   {    unsigned INT32 e;    if( !foo )    return 0;    for( e; e<string_hash.size; e++ ) -  if( foo == string_hash.table[e].str ) +  if( foo == string_hash.table[e] )    return 1;    return 0;   }      struct pike_string *debug_findstring(const struct pike_string *foo)   {    return internal_findstring(foo->str,foo->len,foo->size_shift,do_hash(foo));   }      PMOD_EXPORT void debug_dump_pike_string(struct pike_string *s, INT32 max)
pike.git/src/stralloc.c:1411: Inside #if defined(PIKE_DEBUG)
   else    fprintf(stderr,"\"\n");   }      void dump_stralloc_strings(void)   {    unsigned INT32 e;    struct pike_string *p;    for(e=0;e<string_hash.size;e++)    { -  if(p=string_hash.table[e].str) +  if(p=string_hash.table[e])    {    debug_dump_pike_string(p, 70);   #ifdef DEBUG_MALLOC    debug_malloc_dump_references (p, 2, 1, 0);   #endif    }    }   }      #endif /* PIKE_DEBUG */
pike.git/src/stralloc.c:1648:       return a;   }      /* Returns an unlinked string ready for end_shared_string */   static struct pike_string *realloc_shared_string(struct pike_string *a,    ptrdiff_t size)   {    if(string_may_modify(a))    { -  unlink_pike_string(a,do_hash(a)); +  unlink_pike_string(a);    return realloc_unlinked_string(a, size);    }else{    struct pike_string *r=begin_wide_shared_string(size,a->size_shift);    memcpy(r->str, a->str, a->len<<a->size_shift);    r->flags |= a->flags & STRING_CHECKED_MASK;    r->min = a->min;    r->max = a->max;    free_string(a);    return r;    }
pike.git/src/stralloc.c:1799:    return end_shared_string(b);    }    }    }          /* We now know that the string has the right character size */    if(string_may_modify(a))    {    struct pike_string *old; -  size_t hv = do_hash(a); +     /* One ref - destructive mode */ -  unlink_pike_string(a,hv); +  unlink_pike_string(a);    low_set_index(a, index, c);    CLEAR_STRING_CHECKED(a);    -  old = internal_findstring(a->str, a->len, a->size_shift, hv); +  old = internal_findstring(a->str, a->len, a->size_shift, a->hval);    if (old) {    /* The new string is equal to some old string. */    free_string(a);    add_ref(a = old);    } else { -  link_pike_string(a, hv); +  link_pike_string(a);    }    return a;    }else{    struct pike_string *r;    r=begin_wide_shared_string(a->len,a->size_shift);    memcpy(r->str, a->str, a->len << a->size_shift);    low_set_index(r,index,c);    free_string(a);    return end_shared_string(r);    }
pike.git/src/stralloc.c:1952: Inside #if defined(PIKE_DEBUG)
  {   #ifdef PIKE_DEBUG    if(start < 0 || len<0 || start+len>s->len )    {    Pike_fatal("string_slice, start = %ld, len = %ld, s->len = %ld\n",    DO_NOT_WARN((long)start),    DO_NOT_WARN((long)len),    DO_NOT_WARN((long)s->len));    }   #endif -  if( len == 0) +  if(len == 0)    {    add_ref(empty_pike_string);    return empty_pike_string;    }       if(start==0 && len==s->len)    {    add_ref(s);    return s;    }
pike.git/src/stralloc.c:2096:    }    generic_memcpy(r,MKPCHARP(s,str->size_shift),(end-s)>>str->size_shift);       CALL_AND_UNSET_ONERROR (mojt_uwp);    return end_shared_string(ret);   }      /*** init/exit memory ***/   void init_shared_string_table(void)   { -  stralloc_rehash(); +  stralloc_grow();    empty_pike_string = make_shared_static_string("",0,0);    empty_pike_string->flags |= STRING_CONTENT_CHECKED | STRING_IS_LOWERCASE | STRING_IS_UPPERCASE;    empty_pike_string->min = empty_pike_string->max = 0;   }      #ifdef DO_PIKE_CLEANUP   PMOD_EXPORT struct shared_string_location *all_shared_string_locations;   #endif      
pike.git/src/stralloc.c:2157:    ba_destroy(&string_allocator);   #endif /* DO_PIKE_CLEANUP */   }      void count_string_types() {    unsigned INT32 e;    size_t num_static = 0, num_short = 0;       for (e = 0; e < string_hash.size; e++) {    struct pike_string * s; -  if( (s = string_hash.table[e].str) ) +  if( (s = string_hash.table[e]) )    switch (s->flags & STRING_ALLOC_MASK) {    case STRING_ALLOC_BA:    num_short ++;    break;    case STRING_ALLOC_STATIC:    num_static ++;    break;    }    }   
pike.git/src/stralloc.c:2195:       return size;   }      void count_memory_in_strings(size_t *num, size_t *_size)   {    unsigned INT32 e;    size_t size = 0;    *num = string_hash.num_strings;    -  size+=string_hash.size * sizeof(struct hentry); +  size += string_hash.size * sizeof(struct pike_string *);       for (e = 0; e < string_hash.size; e++) {    struct pike_string *s; -  if( (s = string_hash.table[e].str) ) +  if( (s = string_hash.table[e]) )    size += count_memory_in_string(s);    }       *_size = size;   }      PMOD_EXPORT void visit_string (struct pike_string *s, int action, void *extra)   {    visit_enter(s, T_STRING, extra);    switch (action) {
pike.git/src/stralloc.c:2232:   }      #ifdef PIKE_DEBUG   unsigned gc_touch_all_strings(void)   {    unsigned INT32 e;    unsigned n = 0;    for(e=0;e<string_hash.size;e++)    {    struct pike_string *p; -  if((p = string_hash.table[e].str )) +  if((p = string_hash.table[e]))    debug_gc_touch(p), n++;    }    return n;   }      void gc_mark_all_strings(void)   {    unsigned INT32 e;    for(e=0;e<string_hash.size;e++)    {    struct pike_string *p; -  if( (p = string_hash.table[e].str) ) +  if( (p = string_hash.table[e]) )    gc_is_referenced(p);    }   }   #endif      struct pike_string *next_pike_string (struct pike_string *s)   {    int found = 0;    size_t e = 0;    for(;;)    { -  if( string_hash.table[e].str && found ) -  return string_hash.table[e].str; -  if( string_hash.table[e].str == s ) +  if( string_hash.table[e] && found ) +  return string_hash.table[e]; +  if( string_hash.table[e] == s )    found=1;    e = HMODULO(e+1);    }   }      PMOD_EXPORT void init_string_builder_alloc(struct string_builder *s, ptrdiff_t length, int mag)   {    s->s=begin_wide_shared_string(length,mag);    s->malloced=length;    s->known_shift=0;
pike.git/src/stralloc.c:2295:    to->known_shift = from->known_shift;   }      /* str becomes invalid if successful (i.e. nonzero returned),    * otherwise nothing happens. */   PMOD_EXPORT int init_string_builder_with_string (struct string_builder *s,    struct pike_string *str)   {    if (string_may_modify(str)) {    /* Unlink the string and use it as buffer directly. */ -  unlink_pike_string (str,do_hash(str)); +  unlink_pike_string (str);    str->flags = STRING_NOT_SHARED;    s->s = str;    s->malloced = str->len;    s->known_shift = str->size_shift;    return 1;    }    return 0;   }      PMOD_EXPORT void string_build_mkspace(struct string_builder *s,