From: Jay Freeman (saurik) Date: Sat, 22 Jun 2013 01:46:09 +0000 (-0700) Subject: Reimplement apr_pools using CYPool in libcycript. X-Git-Tag: v0.9.500%b1~58 X-Git-Url: https://git.saurik.com/cycript.git/commitdiff_plain/0cbeddf886b3e6d732c96a8f6a578a755e7ddf66?ds=inline Reimplement apr_pools using CYPool in libcycript. --- diff --git a/Console.cpp b/Console.cpp index 32e4c5f..c2a8761 100644 --- a/Console.cpp +++ b/Console.cpp @@ -60,6 +60,8 @@ #include #include +#include +#include #include @@ -392,8 +394,8 @@ static void Console(CYOptions &options) { else passwd = getpwuid(getuid()); - const char *basedir(pool.sprintf("%s/.cycript", passwd->pw_dir)); - const char *histfile(pool.sprintf("%s/history", basedir)); + const char *basedir(pool.strcat(passwd->pw_dir, "/.cycript", NULL)); + const char *histfile(pool.strcat(basedir, "/history", NULL)); size_t histlines(0); rl_initialize(); @@ -598,6 +600,11 @@ static void *Map(const char *path, size_t *psize) { void InjectLibrary(pid_t pid); int Main(int argc, char const * const argv[], char const * const envp[]) { + _aprcall(apr_initialize()); + + apr_pool_t *pool; + apr_pool_create(&pool, NULL); + bool tty(isatty(STDIN_FILENO)); bool compile(false); CYOptions options; @@ -608,7 +615,6 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { pid_t pid(_not(pid_t)); #endif - CYPool pool; apr_getopt_t *state; _aprcall(apr_getopt_init(&state, pool, argc, argv)); @@ -678,7 +684,7 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { pid = strtoul(arg, &end, 0); if (arg + size != end) { // XXX: arg needs to be escaped in some horrendous way of doom - const char *command(pool.sprintf("ps axc|sed -e '/^ *[0-9]/{s/^ *\\([0-9]*\\)\\( *[^ ]*\\)\\{3\\} *-*\\([^ ]*\\)/\\3 \\1/;/^%s /{s/^[^ ]* //;q;};};d'", arg)); + const char *command(apr_pstrcat(pool, "ps axc|sed -e '/^ *[0-9]/{s/^ *\\([0-9]*\\)\\( *[^ ]*\\)\\{3\\} *-*\\([^ ]*\\)/\\3 \\1/;/^", arg, " /{s/^[^ ]* //;q;};};d'", NULL)); if (FILE *pids = popen(command, "r")) { char value[32]; @@ -850,6 +856,8 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { } } + apr_pool_destroy(pool); + return 0; } diff --git a/Cycript.l.in b/Cycript.l.in index b766a95..87a46af 100644 --- a/Cycript.l.in +++ b/Cycript.l.in @@ -43,7 +43,7 @@ typedef cy::parser::token tk; } while (false) #define A new($pool) -#define Y apr_pstrmemdup($pool, yytext, yyleng) +#define Y $pool.strmemdup(yytext, yyleng) #define I(type, Type, value, highlight) do { \ yylval->type ## _ = A CY ## Type; \ diff --git a/Error.hpp b/Error.hpp index f608e88..3165287 100644 --- a/Error.hpp +++ b/Error.hpp @@ -51,6 +51,8 @@ struct CYPoolError : CYPool pool_; const char *message_; + CYPoolError(const CYPoolError &rhs); + CYPoolError(const char *format, ...); CYPoolError(const char *format, va_list args); diff --git a/Exception.hpp b/Exception.hpp index 598548f..9f6a81a 100644 --- a/Exception.hpp +++ b/Exception.hpp @@ -26,6 +26,9 @@ #include #endif +// XXX: does _assert really need this? +#include + #include "Standard.hpp" class CYPool; diff --git a/Execute.cpp b/Execute.cpp index 7d20679..ac05c66 100644 --- a/Execute.cpp +++ b/Execute.cpp @@ -250,7 +250,7 @@ JSObjectRef CYMakeStruct(JSContextRef context, void *data, sig::Type *type, ffi_ internal->value_ = data; else { size_t size(typical->GetFFI()->size); - void *copy((*internal->pool_)(size)); + void *copy(internal->pool_->malloc(size)); memcpy(copy, data, size); internal->value_ = copy; } @@ -342,7 +342,7 @@ static size_t Nonce_(0); static JSValueRef $cyq(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYPool pool; - const char *name(pool.sprintf("%s%"APR_SIZE_T_FMT"", CYPoolCString(pool, context, arguments[0]), Nonce_++)); + const char *name(pool.strcat(CYPoolCString(pool, context, arguments[0]), pool.itoa(Nonce_++), NULL)); return CYCastJSValue(context, name); } @@ -1219,7 +1219,7 @@ static JSValueRef Type_callAsFunction_toCYON(JSContextRef context, JSObjectRef o const char *type(sig::Unparse(pool, internal->type_)); std::ostringstream str; CYStringify(str, type, strlen(type)); - char *cyon(apr_pstrcat(pool, "new Type(", str.str().c_str(), ")", NULL)); + char *cyon(pool.strcat("new Type(", str.str().c_str(), ")", NULL)); return CYCastJSValue(context, CYJSString(cyon)); } CYCatch(NULL) } @@ -1346,8 +1346,6 @@ void CYInitializeDynamic() { initialized_ = true; else return; - CYInitializeStatic(); - JSObjectMakeArray$ = reinterpret_cast(dlsym(RTLD_DEFAULT, "JSObjectMakeArray")); JSClassDefinition definition; @@ -1459,7 +1457,8 @@ CYJSError::CYJSError(JSContextRef context, const char *format, ...) { va_list args; va_start(args, format); - const char *message(pool.vsprintf(format, args)); + // XXX: there might be a beter way to think about this + const char *message(pool.vsprintf(64, format, args)); va_end(args); value_ = CYCastJSError(context, message); diff --git a/Handler.mm b/Handler.mm index c289c4e..c1e9693 100644 --- a/Handler.mm +++ b/Handler.mm @@ -141,7 +141,7 @@ struct CYClient : } }; -static void * APR_THREAD_FUNC OnClient(void *data) { +static void *OnClient(void *data) { CYClient *client(reinterpret_cast(data)); client->Handle(); delete client; diff --git a/Library.cpp b/Library.cpp index 4b7f115..1259aeb 100644 --- a/Library.cpp +++ b/Library.cpp @@ -57,8 +57,6 @@ _finline size_t iconv_(size_t (*iconv)(iconv_t, Type_, size_t *, char **, size_t #endif CYUTF8String CYPoolUTF8String(CYPool &pool, CYUTF16String utf16) { - _assert(pool != NULL); - const char *in(reinterpret_cast(utf16.data)); iconv_t conversion(_syscall(iconv_open("UTF-8", UCS_2_INTERNAL))); @@ -80,8 +78,6 @@ CYUTF8String CYPoolUTF8String(CYPool &pool, CYUTF16String utf16) { } CYUTF16String CYPoolUTF16String(CYPool &pool, CYUTF8String utf8) { - _assert(pool != NULL); - const char *in(utf8.data); iconv_t conversion(_syscall(iconv_open(UCS_2_INTERNAL, "UTF-8"))); @@ -273,18 +269,7 @@ extern "C" void CydgetMemoryParse(const uint16_t **data, size_t *size) { *size = utf16.size; } -static bool initialized_; - -void CYInitializeStatic() { - if (!initialized_) - initialized_ = true; - else return; - - _aprcall(apr_initialize()); -} - CYPool &CYGetGlobalPool() { - CYInitializeStatic(); static CYPool pool; return pool; } @@ -301,13 +286,20 @@ const char *CYPoolError::PoolCString(CYPool &pool) const { return pool.strdup(message_); } +CYPoolError::CYPoolError(const CYPoolError &rhs) : + message_(pool_.strdup(rhs.message_)) +{ +} + CYPoolError::CYPoolError(const char *format, ...) { va_list args; va_start(args, format); - message_ = pool_.vsprintf(format, args); + // XXX: there might be a beter way to think about this + message_ = pool_.vsprintf(64, format, args); va_end(args); } CYPoolError::CYPoolError(const char *format, va_list args) { - message_ = pool_.vsprintf(format, args); + // XXX: there might be a beter way to think about this + message_ = pool_.vsprintf(64, format, args); } diff --git a/Mach/Inject.cpp b/Mach/Inject.cpp index 3f4923b..dffe766 100644 --- a/Mach/Inject.cpp +++ b/Mach/Inject.cpp @@ -43,7 +43,7 @@ void InjectLibrary(pid_t pid) { depth = (depth + sizeof(uintptr_t) + 1) / sizeof(uintptr_t) * sizeof(uintptr_t); CYPool pool; - uint8_t *local(reinterpret_cast(pool(depth))); + uint8_t *local(pool.malloc(depth)); Baton *baton(reinterpret_cast(local)); baton->__pthread_set_self = &__pthread_set_self; diff --git a/Makefile.am b/Makefile.am index a540423..77add03 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ AM_CPPFLAGS += -include $(srcdir)/config.h -include $(srcdir)/unconfig.h lib_LTLIBRARIES = libcycript.la libcycript_la_SOURCES = Highlight.cpp Network.cpp Output.cpp Parser.cpp Replace.cpp libcycript_la_LDFLAGS = -no-undefined -avoid-version -export-dynamic -libcycript_la_LIBADD = $(LTLIBAPR) $(LTLIBFFI) $(LTLIBICONV) -ldl +libcycript_la_LIBADD = $(LTLIBFFI) $(LTLIBICONV) -ldl libcycript_la_SOURCES += Cycript.tab.cc libcycript_la_SOURCES += lex.cy.cpp diff --git a/Makefile.in b/Makefile.in index c9fc785..e83000e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -135,7 +135,7 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__DEPENDENCIES_1 = libcycript_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) am__libcycript_la_SOURCES_DIST = Highlight.cpp Network.cpp Output.cpp \ Parser.cpp Replace.cpp Cycript.tab.cc lex.cy.cpp \ sig/ffi_type.cpp sig/parse.cpp sig/copy.cpp Bridge.cpp \ @@ -482,7 +482,7 @@ libcycript_la_SOURCES = Highlight.cpp Network.cpp Output.cpp \ Parser.cpp Replace.cpp Cycript.tab.cc lex.cy.cpp \ $(am__append_1) $(am__append_6) $(am__append_7) libcycript_la_LDFLAGS = -no-undefined -avoid-version -export-dynamic -libcycript_la_LIBADD = $(LTLIBAPR) $(LTLIBFFI) $(LTLIBICONV) -ldl +libcycript_la_LIBADD = $(LTLIBFFI) $(LTLIBICONV) -ldl cycript_SOURCES = Console.cpp Display.cpp $(am__append_8) cycript_LDADD = libcycript.la $(LTLIBAPR) $(LTLIBREADLINE) $(LTLIBTERMCAP) -ldl ldid = true diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index 44307e2..24269e2 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -185,15 +185,11 @@ Type_ CYPoolRelease(CYPool *pool, Type_ object) { /* }}} */ /* Objective-C Strings {{{ */ const char *CYPoolCString(CYPool &pool, JSContextRef context, NSString *value) { - if (pool == NULL) - return [value UTF8String]; - else { - size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); - char *string(new(pool) char[size]); - if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding]) - throw CYJSError(context, "[NSString getCString:maxLength:encoding:] == NO"); - return string; - } + size_t size([value maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); + char *string(new(pool) char[size]); + if (![value getCString:string maxLength:size encoding:NSUTF8StringEncoding]) + throw CYJSError(context, "[NSString getCString:maxLength:encoding:] == NO"); + return string; } JSStringRef CYCopyJSString(JSContextRef context, NSString *value) { diff --git a/Pooling.hpp b/Pooling.hpp index 854113e..bd37c5c 100644 --- a/Pooling.hpp +++ b/Pooling.hpp @@ -23,18 +23,26 @@ #define CYCRIPT_POOLING_HPP #include +#include #include +#include -#include -#include +#include + +#include #include "Exception.hpp" #include "Local.hpp" #include "Standard.hpp" +class CYPool; +_finline void *operator new(size_t size, CYPool &pool); +_finline void *operator new [](size_t size, CYPool &pool); + class CYPool { private: - apr_pool_t *pool_; + uint8_t *data_; + size_t size_; struct Cleaner { Cleaner *next_; @@ -49,64 +57,137 @@ class CYPool { } } *cleaner_; + static _finline size_t align(size_t size) { + // XXX: alignment is more complex than this + return (size + 7) & ~0x3; + } + + CYPool(const CYPool &); + public: CYPool() : + data_(NULL), + size_(0), cleaner_(NULL) { - _aprcall(apr_pool_create(&pool_, NULL)); } ~CYPool() { - for (Cleaner *cleaner(cleaner_); cleaner_ != NULL; cleaner_ = cleaner_->next_) + for (Cleaner *cleaner(cleaner_); cleaner != NULL; ) { + Cleaner *next(cleaner->next_); (*cleaner->code_)(cleaner->data_); - apr_pool_destroy(pool_); + cleaner = next; + } } - void Clear() { - apr_pool_clear(pool_); - } + template + Type_ *malloc(size_t size) { + size = align(size); + + if (size > size_) { + // XXX: is this an optimal malloc size? + size_ = std::max(size, size + align(sizeof(Cleaner))); + data_ = reinterpret_cast(::malloc(size_)); + atexit(free, data_); + _assert(size <= size_); + } - operator apr_pool_t *() const { - return pool_; + void *data(data_); + data_ += size; + size_ -= size; + return reinterpret_cast(data); } - void *operator()(size_t size) const { - return apr_palloc(pool_, size); + char *strdup(const char *data) { + return reinterpret_cast(memdup(data, strlen(data) + 1)); } - char *strdup(const char *data) const { - return apr_pstrdup(pool_, data); + void *memdup(const void *data, size_t size) { + void *copy(malloc(size)); + memcpy(copy, data, size); + return copy; } char *strndup(const char *data, size_t size) const { - return apr_pstrndup(pool_, data, size); + return strmemdup(data, strnlen(data, size)); } char *strmemdup(const char *data, size_t size) const { - return apr_pstrmemdup(pool_, data, size); + char *copy(new char[size + 1]); + memcpy(copy, data, size); + copy[size] = '\0'; + return copy; } - char *sprintf(const char *format, ...) const { + // XXX: this could be made much more efficient + __attribute__((__sentinel__)) + char *strcat(const char *data, ...) { + size_t size(strlen(data)); { + va_list args; + va_start(args, data); + + while (const char *arg = va_arg(args, const char *)) + size += strlen(arg); + + va_end(args); + } + + char *copy(malloc(size + 1)); { + va_list args; + va_start(args, data); + + size_t offset(strlen(data)); + memcpy(copy, data, offset); + + while (const char *arg = va_arg(args, const char *)) { + size_t size(strlen(arg)); + memcpy(copy + offset, arg, size); + offset += size; + } + + va_end(args); + } + + copy[size] = '\0'; + return copy; + } + + // XXX: most people using this might should use sprintf + char *itoa(long value) { + return sprintf(16, "%ld", value); + } + + __attribute__((__format__(__printf__, 3, 4))) + char *sprintf(size_t size, const char *format, ...) { va_list args; va_start(args, format); - char *data(vsprintf(format, args)); + char *copy(vsprintf(size, format, args)); va_end(args); - return data; + return copy; } - char *vsprintf(const char *format, va_list args) const { - return apr_pvsprintf(pool_, format, args); + char *vsprintf(size_t size, const char *format, va_list args) { + va_list copy; + va_copy(copy, args); + char buffer[size]; + int writ(vsnprintf(buffer, size, format, copy)); + va_end(copy); + _assert(writ >= 0); + + if (size_t(writ) >= size) + return vsprintf(writ + 1, format, args); + return strmemdup(buffer, writ); } void atexit(void (*code)(void *), void *data = NULL); }; _finline void *operator new(size_t size, CYPool &pool) { - return pool(size); + return pool.malloc(size); } _finline void *operator new [](size_t size, CYPool &pool) { - return pool(size); + return pool.malloc(size); } _finline void CYPool::atexit(void (*code)(void *), void *data) { @@ -132,7 +213,7 @@ struct CYData { } static void *operator new(size_t size, CYPool &pool) { - void *data(pool(size)); + void *data(pool.malloc(size)); reinterpret_cast(data)->pool_ = &pool; return data; } @@ -170,7 +251,7 @@ struct CYPoolAllocator { } pointer allocate(size_type size, const void *hint = 0) { - return reinterpret_cast((*pool_)(size)); + return pool_->malloc(size); } void deallocate(pointer data, size_type size) { diff --git a/Replace.cpp b/Replace.cpp index 1e0a5ca..de404d5 100644 --- a/Replace.cpp +++ b/Replace.cpp @@ -210,7 +210,7 @@ void CYContext::NonLocal(CYStatement *&statements) { } CYIdentifier *CYContext::Unique() { - return $ CYIdentifier($pool.sprintf("$cy%u", unique_++)); + return $ CYIdentifier($pool.strcat("$cy", $pool.itoa(unique_++), NULL)); } CYStatement *CYContinue::Replace(CYContext &context) { @@ -555,7 +555,7 @@ CYNumber *CYNumber::Number(CYContext &context) { CYString *CYNumber::String(CYContext &context) { // XXX: there is a precise algorithm for this - return $S($pool.sprintf("%.17g", Value())); + return $S($pool.sprintf(24, "%.17g", Value())); } CYExpression *CYObject::Replace(CYContext &context) { @@ -619,7 +619,7 @@ void CYProgram::Replace(CYContext &context) { const char *name; if (context.options_.verbose_) - name = $pool.sprintf("$%"APR_SIZE_T_FMT"", offset); + name = $pool.strcat("$", $pool.itoa(offset), NULL); else { char id[8]; id[7] = '\0'; diff --git a/cycript.hpp b/cycript.hpp index 841cf16..52accef 100644 --- a/cycript.hpp +++ b/cycript.hpp @@ -28,8 +28,6 @@ #include "Pooling.hpp" #include "String.hpp" -void CYInitializeStatic(); - bool CYRecvAll_(int socket, uint8_t *data, size_t size); bool CYSendAll_(int socket, const uint8_t *data, size_t size); diff --git a/sig/ffi_type.cpp b/sig/ffi_type.cpp index 7d552ba..7abe6fd 100644 --- a/sig/ffi_type.cpp +++ b/sig/ffi_type.cpp @@ -64,7 +64,7 @@ ffi_type *ObjectiveC(CYPool &pool, struct Type *type) { case array_P: { // XXX: this is really lame - ffi_type *aggregate(reinterpret_cast(pool(sizeof(ffi_type)))); + ffi_type *aggregate(new(pool) ffi_type()); aggregate->size = 0; aggregate->alignment = 0; aggregate->type = FFI_TYPE_STRUCT; @@ -72,7 +72,7 @@ ffi_type *ObjectiveC(CYPool &pool, struct Type *type) { ffi_type *element(ObjectiveC(pool, type->data.data.type)); size_t size(type->data.data.size); - aggregate->elements = reinterpret_cast(pool((size + 1) * sizeof(ffi_type *))); + aggregate->elements = new(pool) ffi_type *[size + 1]; for (size_t i(0); i != size; ++i) aggregate->elements[i] = element; aggregate->elements[size] = NULL; @@ -98,12 +98,12 @@ ffi_type *ObjectiveC(CYPool &pool, struct Type *type) { case void_P: return &ffi_type_void; case struct_P: { - ffi_type *aggregate(reinterpret_cast(pool(sizeof(ffi_type)))); + ffi_type *aggregate(new(pool) ffi_type()); aggregate->size = 0; aggregate->alignment = 0; aggregate->type = FFI_TYPE_STRUCT; - aggregate->elements = reinterpret_cast(pool((type->data.signature.count + 1) * sizeof(ffi_type *))); + aggregate->elements = new(pool) ffi_type *[type->data.signature.count + 1]; sig_ffi_types(pool, &ObjectiveC, &type->data.signature, aggregate->elements); aggregate->elements[type->data.signature.count] = NULL; @@ -162,7 +162,7 @@ void sig_ffi_cif( size_t offset ) { if (types == NULL) - types = reinterpret_cast(pool((signature->count - 1) * sizeof(ffi_type *))); + types = new(pool) ffi_type *[signature->count - 1]; ffi_type *type = (*sig_ffi_type)(pool, signature->elements[0].type); sig_ffi_types(pool, sig_ffi_type, signature, types, 1 + skip, offset); ffi_status status = ffi_prep_cif(cif, FFI_DEFAULT_ABI, signature->count - 1 - skip + offset, type, types); diff --git a/sig/parse.cpp b/sig/parse.cpp index 8de5eb4..1bbd7a4 100644 --- a/sig/parse.cpp +++ b/sig/parse.cpp @@ -34,7 +34,7 @@ struct Type *Parse_(CYPool &pool, const char **name, char eos, bool named, Callb /* XXX: I really screwed up this time */ void *prealloc_(CYPool &pool, void *odata, size_t osize, size_t nsize) { - void *ndata(pool(nsize)); + void *ndata(pool.malloc(nsize)); memcpy(ndata, odata, osize); return ndata; } @@ -233,7 +233,7 @@ const char *Unparse(CYPool &pool, struct Signature *signature) { for (offset = 0; offset != signature->count; ++offset) { const char *type = Unparse(pool, signature->elements[offset].type); - value = apr_pstrcat(pool, value, type, NULL); + value = pool.strcat(value, type, NULL); } return value; @@ -242,11 +242,11 @@ const char *Unparse(CYPool &pool, struct Signature *signature) { const char *Unparse_(CYPool &pool, struct Type *type) { switch (type->primitive) { case typename_P: return "#"; - case union_P: return pool.sprintf("(%s)", Unparse(pool, &type->data.signature)); + case union_P: return pool.strcat("(", Unparse(pool, &type->data.signature), ")", NULL); case string_P: return "*"; case selector_P: return ":"; case block_P: return "@?"; - case object_P: return type->name == NULL ? "@" : pool.sprintf("@\"%s\"", type->name); + case object_P: return type->name == NULL ? "@" : pool.strcat("@\"", type->name, "\"", NULL); case boolean_P: return "B"; case uchar_P: return "C"; case uint_P: return "I"; @@ -256,11 +256,11 @@ const char *Unparse_(CYPool &pool, struct Type *type) { case array_P: { const char *value = Unparse(pool, type->data.data.type); - return pool.sprintf("[%"APR_SIZE_T_FMT"%s]", type->data.data.size, value); + return pool.strcat("[", pool.itoa(type->data.data.size), value, "]", NULL); } break; - case pointer_P: return pool.sprintf("^%s", type->data.data.type == NULL ? "v" : Unparse(pool, type->data.data.type)); - case bit_P: return pool.sprintf("b%"APR_SIZE_T_FMT"", type->data.data.size); + case pointer_P: return pool.strcat("^", type->data.data.type == NULL ? "v" : Unparse(pool, type->data.data.type), NULL); + case bit_P: return pool.strcat("b", pool.itoa(type->data.data.size), NULL); case char_P: return "c"; case double_P: return "d"; case float_P: return "f"; @@ -269,7 +269,7 @@ const char *Unparse_(CYPool &pool, struct Type *type) { case longlong_P: return "q"; case short_P: return "s"; case void_P: return "v"; - case struct_P: return pool.sprintf("{%s=%s}", type->name == NULL ? "?" : type->name, Unparse(pool, &type->data.signature)); + case struct_P: return pool.strcat("{", type->name == NULL ? "?" : type->name, "=", Unparse(pool, &type->data.signature), "}", NULL); } _assert(false); @@ -287,26 +287,27 @@ const char *Unparse(CYPool &pool, struct Type *type) { #define iovec_(base, size) \ (struct iovec) {const_cast(base), size} - struct iovec parts[8]; - memset(parts, 0, sizeof(parts)); + size_t size(strlen(base)); + char buffer[7 + size]; + size_t offset(0); if ((type->flags & JOC_TYPE_INOUT) != 0) - parts[0] = iovec_("N", 1); + buffer[offset++] = 'N'; if ((type->flags & JOC_TYPE_IN) != 0) - parts[1] = iovec_("n", 1); + buffer[offset++] = 'n'; if ((type->flags & JOC_TYPE_BYCOPY) != 0) - parts[2] = iovec_("O", 1); + buffer[offset++] = 'O'; if ((type->flags & JOC_TYPE_OUT) != 0) - parts[3] = iovec_("o", 1); + buffer[offset++] = 'o'; if ((type->flags & JOC_TYPE_BYREF) != 0) - parts[4] = iovec_("R", 1); + buffer[offset++] = 'R'; if ((type->flags & JOC_TYPE_CONST) != 0) - parts[5] = iovec_("r", 1); + buffer[offset++] = 'r'; if ((type->flags & JOC_TYPE_ONEWAY) != 0) - parts[6] = iovec_("V", 1); + buffer[offset++] = 'V'; - parts[7] = iovec_(base, strlen(base)); - return apr_pstrcatv(pool, parts, 8, NULL); + memcpy(buffer + offset, base, size); + return pool.strmemdup(buffer, offset + size); } }