Hi Pietro.
OK. Thanks! > This is a v2 of libga68: Don't call free on gc-allocated strings, but > that commit message is incorrect now. > > Since only posix prelude functions use the conversion function, and they > add a trailling null and pass the result to functions that work on char*, > I decided to add the trailling null and return a char* anyway. > -- >8 -- > _libga68_u32_to_u8 called free on the result buffer on error, but the > buffer is allocated by the GC, so calling free on it is incorrect. > > Instead of using the GC, use the internal malloc because this is an > internal function. > > Remove the resultbuf parameter from the _libga68_u32_to_u8 since all > callers used NULL for it. > > Last but not least, return a null-terminated char* from > _libga68_u32_to_u8. > > libga68/ChangeLog: > > * ga68-alloc.c (_libga68_realloc_internal): New function. > * ga68-posix.c (_libga68_posixperror): Adjust calls to > _libga68_u32_to_u8. > (_libga68_posixfopen): Likewise. > (_libga68_posixcreat): Likewise. > (_libga68_posixgetenv): Likewise. > (_libga68_posixfputs): Likewise. > (_libga68_posixfconnect): Likewise. > * ga68-unistr.c (_libga68_u32_to_u8): Use internal allocator. > * ga68.h (_libga68_realloc_internal): New prototype. > (_libga68_u32_to_u8): Update prototype. > > Signed-off-by: Pietro Monteiro <[email protected]> > --- > libga68/ga68-alloc.c | 9 ++++++ > libga68/ga68-posix.c | 36 +++++++++------------ > libga68/ga68-unistr.c | 73 ++++++++++++++++++------------------------- > libga68/ga68.h | 5 +-- > 4 files changed, 57 insertions(+), 66 deletions(-) > > diff --git a/libga68/ga68-alloc.c b/libga68/ga68-alloc.c > index df8a8956c52..1edc148db69 100644 > --- a/libga68/ga68-alloc.c > +++ b/libga68/ga68-alloc.c > @@ -42,6 +42,15 @@ _libga68_malloc_internal (size_t size) > return res; > } > > +void * > +_libga68_realloc_internal (void *ptr, size_t size) > +{ > + void *res = (void *) realloc (ptr, size); > + if (!res) > + _libga68_abort ("Virtual memory exhausted\n"); > + return res; > +} > + > #if LIBGA68_WITH_GC > #include <gc/gc.h> > > diff --git a/libga68/ga68-posix.c b/libga68/ga68-posix.c > index b6fba202497..ef137933774 100644 > --- a/libga68/ga68-posix.c > +++ b/libga68/ga68-posix.c > @@ -57,13 +57,14 @@ void > _libga68_posixperror (uint32_t *s, size_t len, size_t stride) > { > size_t u8len; > - uint8_t *u8str = _libga68_u32_to_u8 (s, len, stride, NULL, &u8len); > + uint8_t *u8str = _libga68_u32_to_u8 (s, len, stride, &u8len); > > const char *errstr = strerror (_libga68_errno); > (void) write (2, u8str, u8len); > (void) write (2, ": ", 2); > (void) write (2, errstr, strlen (errstr)); > (void) write (2, "\n", 1); > + _libga68_free_internal (u8str); > } > > uint32_t * > @@ -95,11 +96,7 @@ _libga68_posixfopen (const uint32_t *pathname, size_t len, > size_t stride, > int fd; > int openflags = 0; > size_t u8len; > - const uint8_t *u8pathname = _libga68_u32_to_u8 (pathname, len, stride, > NULL, > - &u8len); > - char *filepath = (char *) _libga68_malloc_internal (u8len + 1); > - memcpy (filepath, u8pathname, u8len); > - filepath[u8len] = '\0'; > + const char *filepath = _libga68_u32_to_u8 (pathname, len, stride, &u8len); > > /* Default mode: try read-write initially. > If that fails, then try read-only. > @@ -141,11 +138,11 @@ _libga68_posixcreat (uint32_t *pathname, size_t len, > size_t stride, > uint32_t mode) > { > size_t u8len; > - uint8_t *u8pathname = _libga68_u32_to_u8 (pathname, len, stride, NULL, > &u8len); > - u8pathname[u8len] = '\0'; > + const char *filepath = _libga68_u32_to_u8 (pathname, len, stride, &u8len); > > - int res = creat (u8pathname, mode); > + int res = creat (filepath, mode); > _libga68_errno = errno; > + _libga68_free_internal (filepath); > return res; > } > > @@ -189,14 +186,11 @@ void > _libga68_posixgetenv (uint32_t *s, size_t len, size_t stride, > uint32_t **r, size_t *rlen) > { > - size_t varlen; > - char *varname = _libga68_u32_to_u8 (s, len, stride, NULL, &varlen); > + size_t u8len; > + const char *varname = _libga68_u32_to_u8 (s, len, stride, &u8len); > > - char *var = _libga68_malloc_internal (varlen + 1); > - memcpy (var, varname, varlen); > - var[varlen] = '\0'; > - char *val = getenv (var); > - _libga68_free_internal (var); > + char *val = getenv (varname); > + _libga68_free_internal (varname); > > if (val == NULL) > { > @@ -222,10 +216,11 @@ int > _libga68_posixfputs (int fd, uint32_t *s, size_t len, size_t stride) > { > size_t u8len; > - uint8_t *u8str = _libga68_u32_to_u8 (s, len, stride, NULL, &u8len); > + const char *u8str = _libga68_u32_to_u8 (s, len, stride, &u8len); > > ssize_t ret = write (fd, u8str, u8len); > _libga68_errno = errno; > + _libga68_free_internal (u8str); > if (ret == -1) > return 0; > else > @@ -371,7 +366,7 @@ _libga68_posixfconnect (uint32_t *str, size_t len, size_t > stride, > int port) > { > size_t u8len; > - uint8_t *u8host = _libga68_u32_to_u8 (str, len, stride, NULL, &u8len); > + const char *host = _libga68_u32_to_u8 (str, len, stride, &u8len); > > /* Create a stream socket. */ > int fd = socket (AF_INET, SOCK_STREAM, 0); > @@ -380,9 +375,6 @@ _libga68_posixfconnect (uint32_t *str, size_t len, size_t > stride, > goto error; > > /* Lookup the specified host. */ > - char *host = _libga68_malloc_internal (u8len + 1); > - memcpy (host, u8host, u8len); > - host[u8len] = '\0'; > struct hostent *server = gethostbyname (host); > if (server == NULL) > { > @@ -409,8 +401,8 @@ _libga68_posixfconnect (uint32_t *str, size_t len, size_t > stride, > > close_fd_and_error: > close (fd); > - error: > _libga68_free_internal (host); > + error: > return -1; > } > > diff --git a/libga68/ga68-unistr.c b/libga68/ga68-unistr.c > index 2a71313c181..e37bd8c852d 100644 > --- a/libga68/ga68-unistr.c > +++ b/libga68/ga68-unistr.c > @@ -305,34 +305,26 @@ _libga68_u8_uctomb (uint8_t *s, uint32_t uc, ptrdiff_t > n) > return -2; > } > > -/* Convert UCS-4 to UTF-8 */ > - > -uint8_t * > -_libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t stride, > - uint8_t *resultbuf, size_t *lengthp) > +/* Convert S of size N with stride STRIDE UCS-4 to UTF-8. > + Returns a pointer to the converted string with a traiiling '\0'. > + The string length, not counting the trailling '\0', is returned on > LENGTHP. > + Returns NULL on error. > + Callers *must* call _libga68_free_internal on a non-null result. */ > + > +char * > +_libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t stride, size_t > *lengthp) > { > const uint32_t *s_end; > /* Output string accumulator. */ > - uint8_t *result; > - size_t allocated; > - size_t length; > + uint8_t *result = NULL; > + size_t allocated = 0; > + size_t length = 0; > > stride = stride / sizeof (uint32_t); > s_end = s + (n * stride); > > - if (resultbuf != NULL) > - { > - result = resultbuf; > - allocated = *lengthp; > - } > - else > - { > - result = NULL; > - allocated = 0; > - } > - length = 0; > /* Invariants: > - result is either == resultbuf or == NULL or malloc-allocated. > + result is either == NULL or allocated by the internal malloc. > If length > 0, then result != NULL. */ > > while (s < s_end) > @@ -350,8 +342,8 @@ _libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t > stride, > count = _libga68_u8_uctomb (result + length, uc, allocated - length); > if (count == -1) > { > - if (!(result == resultbuf || result == NULL)) > - free (result); > + if (result != NULL) > + _libga68_free_internal (result); > errno = EILSEQ; > return NULL; > } > @@ -362,15 +354,12 @@ _libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t > stride, > allocated = (allocated > 0 ? 2 * allocated : 12); > if (length + 6 > allocated) > allocated = length + 6; > - if (result == resultbuf || result == NULL) > - memory = (uint8_t *) _libga68_malloc_leaf (allocated * sizeof > (uint8_t)); > + if (result == NULL) > + memory = (uint8_t *) _libga68_malloc_internal (allocated * sizeof > (uint8_t)); > else > memory = > - (uint8_t *) _libga68_realloc (result, allocated * sizeof > (uint8_t)); > + (uint8_t *) _libga68_realloc_internal (result, allocated * sizeof > (uint8_t)); > > - if (result == resultbuf && length > 0) > - memcpy ((char *) memory, (char *) result, > - length * sizeof (uint8_t)); > result = memory; > count = _libga68_u8_uctomb (result + length, uc, allocated - > length); > if (count < 0) > @@ -384,26 +373,26 @@ _libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t > stride, > if (result == NULL) > { > /* Return a non-NULL value. NULL means error. */ > - result = (uint8_t *) _libga68_malloc_leaf (1); > - if (result == NULL) > - { > - errno = ENOMEM; > - return NULL; > - } > + result = (uint8_t *) _libga68_malloc_internal (1); > } > } > - else if (result != resultbuf && length < allocated) > + else > { > - /* Shrink the allocated memory if possible. */ > - uint8_t *memory; > - > - memory = (uint8_t *) _libga68_realloc_unchecked (result, length * > sizeof (uint8_t)); > - if (memory != NULL) > - result = memory; > + if (length + 1 != allocated) > + { > + /* Resize the allocated memory to fit the string plus the trailling > NULL. */ > + uint8_t *memory; > + > + memory = > + (uint8_t *) _libga68_realloc_internal (result, > + (length +1) * sizeof > (uint8_t)); > + result = memory; > + } > + result[length] = 0x0; > } > > *lengthp = length; > - return result; > + return (char *) result; > } > > /* Used by ga68_u8_to_u32 below. */ > diff --git a/libga68/ga68.h b/libga68/ga68.h > index 8d1cf20c162..316a9e318d5 100644 > --- a/libga68/ga68.h > +++ b/libga68/ga68.h > @@ -73,6 +73,7 @@ void *_libga68_malloc (size_t size); > void *_libga68_malloc_leaf (size_t size); > void *_libga68_malloc_internal (size_t size) GA68_HIDDEN; > void *_libga68_realloc (void *ptr, size_t size) GA68_HIDDEN; > +void *_libga68_realloc_internal (void *ptr, size_t size) GA68_HIDDEN; > void *_libga68_realloc_unchecked (void *ptr, size_t size) GA68_HIDDEN; > void _libga68_free_internal (void *ptr) GA68_HIDDEN; > > @@ -117,8 +118,8 @@ int _libga68_u32_cmp2 (const uint32_t *s1, size_t n1, > size_t stride1, > const uint32_t *s2, size_t n2, size_t stride2); > int _libga68_u8_uctomb (uint8_t *s, uint32_t uc, ptrdiff_t n) GA68_HIDDEN; > int _libga68_u8_mbtouc (uint32_t *puc, const uint8_t *s, size_t n) > GA68_HIDDEN; > -uint8_t *_libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t stride, > - uint8_t *resultbuf, size_t *lengthp) GA68_HIDDEN; > +char *_libga68_u32_to_u8 (const uint32_t *s, size_t n, size_t stride, > + size_t *lengthp) GA68_HIDDEN; > uint32_t *_libga68_u8_to_u32 (const uint8_t *s, size_t n, > uint32_t *resultbuf, size_t *lengthp);
