1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 Ericsson Telecom AB
3 // All rights reserved. This program and the accompanying materials
4 // are made available under the terms of the Eclipse Public License v1.0
5 // which accompanies this distribution, and is available at
6 // http://www.eclipse.org/legal/epl-v10.html
7 ///////////////////////////////////////////////////////////////////////////////
14 #undef mprintf_va_list
16 #undef mputprintf_va_list
33 * work-around for missing va_copy() in GCC
35 #if defined(__GNUC__) && !defined(va_copy)
37 # define va_copy(dest, src) __va_copy(dest, src)
39 # define va_copy(dest, src) (dest) = (src)
43 /** Initial buffer size for mprintf */
46 /** @def MEMORY_DEBUG_ADDRESS
48 * If you want to catch memory management functions (malloc, realloc,
49 * free) which operate on a given address, define this macro and set
50 * memory_debug_address to the address you want to monitor.
52 * @note This macro has no effect if \c MEMORY_DEBUG is not defined
54 #ifdef DOXYGEN_SPECIAL
55 /* Make the macro visible to Doxygen */
56 #define MEMORY_DEBUG_ADDRESS
59 #ifdef MEMORY_DEBUG_ADDRESS
60 /** @brief Memory checkpoint address. */
61 void *memory_debug_address
= NULL
;
63 /** @brief Memory checkpoint ordinal. */
64 size_t memory_debug_ordinal
= (size_t)-1;
68 * @name Number of memory allocations and frees performed.
70 * @note These are tracked even without MEMORY_DEBUG.
72 static size_t malloc_count
= 0, free_count
= 0;
76 * If preprocessor symbol \c MEMORY_DEBUG is defined the memory
77 * management routines do some self-checks against improper use. This
78 * implies extra memory usage and significant performance penalty.
82 #define FILENAME_FORMAT "%s:%d: "
84 /* Currently allocated memory amount, peak, and number of allocations */
85 static size_t allocated_size
= 0, peak_size
= 0;
86 static unsigned int alloc_count
= 0;
87 /* Sum of all the allocated amounts */
88 static unsigned long long total_allocated
= 0;
90 typedef struct memory_block_struct
{
92 struct memory_block_struct
*prev
, *next
;
93 const char *filename
; /* pointer to string literal */
95 unsigned int ordinal
; /* The ordinal which uniquely identifies this allocation */
96 void *magic
; /* only to reserve some place for the magic guard */
97 double begin
; /* beginning of useful memory with proper alignment */
100 static memory_block
*list_head
= NULL
, *list_tail
= NULL
;
102 static void add_to_list(memory_block
*block_ptr
)
104 block_ptr
->prev
= list_tail
;
105 block_ptr
->next
= NULL
;
106 if (list_tail
!= NULL
) list_tail
->next
= block_ptr
;
107 else list_head
= block_ptr
;
108 list_tail
= block_ptr
;
111 static void remove_from_list(memory_block
*block_ptr
)
113 if (block_ptr
->prev
!= NULL
)
114 block_ptr
->prev
->next
= block_ptr
->next
;
115 else list_head
= block_ptr
->next
;
116 if (block_ptr
->next
!= NULL
)
117 block_ptr
->next
->prev
= block_ptr
->prev
;
118 else list_tail
= block_ptr
->prev
;
121 /* Layout of memory (allocated in one chunk)
122 * +----------+ <--- block_ptr
134 * +----------+ +-----------+
135 * | begin | | user data |
139 * +-----------+ +-----------+
144 * The magic values initially contain the value of block_ptr.
145 * When the block is freed, a bit-flipped value is written instead.
146 * During realloc and free, the magic values are checked to match block_ptr.
147 * If they don't, the a memory overrun or underrun has occurred
148 * (except if the magic value happens to match the bit-flipped block_ptr,
149 * in which case it's likely a double-free).
152 static void set_magic_values(memory_block
*block_ptr
)
154 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
155 memcpy(&block_ptr
->magic
, &block_ptr
, sizeof(block_ptr
));
156 memcpy(ptr
+ block_ptr
->size
, &block_ptr
, sizeof(block_ptr
));
159 static void check_magic_values(const char *filename
, int line
,
160 memory_block
*block_ptr
, int is_realloc
)
162 void *inv_ptr
= (void*)(~(size_t)block_ptr
);
163 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
164 /* compare the magic */
165 if (memcmp(&block_ptr
->magic
, &block_ptr
, sizeof(block_ptr
))) {
168 if (memcmp(&block_ptr
->magic
, &inv_ptr
, sizeof(inv_ptr
)))
169 err_str
= "memory corruption";
170 else err_str
= "duplicate free/realloc";
172 fprintf(stderr
, FILENAME_FORMAT
, filename
, line
);
174 fprintf(stderr
, "Fatal error: %s detected at block begin when %s "
175 "pointer %p.\n", err_str
, is_realloc
? "reallocating" : "freeing",
177 if (block_ptr
->filename
) fprintf(stderr
,
178 FILENAME_FORMAT
"Last freed here.\n", block_ptr
->filename
, block_ptr
->lineno
);
181 memcpy(&block_ptr
->magic
, &inv_ptr
, sizeof(inv_ptr
));/*invert magic*/
182 if (memcmp(ptr
+ block_ptr
->size
, &block_ptr
, sizeof(block_ptr
))) {
184 fprintf(stderr
, FILENAME_FORMAT
, filename
, line
);
186 fprintf(stderr
, "Fatal error: memory corruption detected "
187 "at block end when %s pointer %p.\n",
188 is_realloc
? "reallocating" : "freeing", ptr
);
189 if (block_ptr
->filename
) fprintf(stderr
,
190 FILENAME_FORMAT
"Last freed here.\n", block_ptr
->filename
, block_ptr
->lineno
);
193 memcpy(ptr
+ block_ptr
->size
, &inv_ptr
, sizeof(inv_ptr
));
194 block_ptr
->filename
= filename
;
195 block_ptr
->lineno
= line
;
198 /** @def MEMORY_DEBUG_FREE
199 * @brief Enable checking for uses of unallocated/deallocated memory areas.
201 * If preprocessor symbol \c MEMORY_DEBUG_FREE is defined the memory
202 * management routines can verify that unused and deallocated memory areas
203 * are not written accidentally by the program after calling \a Free().
204 * This verification can be done using functions \a check_mem_leak() or
205 * \a check_mem_corrupt().
207 * Note: This functionality can significantly increase the memory requirements
208 * of the program since the deallocated blocks cannot be recycled. They are
209 * not returned to the system using \a free() until the end of the program run.
211 #ifdef DOXYGEN_SPECIAL
212 /* Make the macro visible to Doxygen */
213 #define MEMORY_DEBUG_FREE
216 #ifdef MEMORY_DEBUG_FREE
218 static memory_block
*free_list_head
= NULL
, *free_list_tail
= NULL
;
220 static void add_to_free_list(memory_block
*block_ptr
)
222 block_ptr
->prev
= free_list_tail
;
223 block_ptr
->next
= NULL
;
224 if (free_list_tail
!= NULL
) free_list_tail
->next
= block_ptr
;
225 else free_list_head
= block_ptr
;
226 free_list_tail
= block_ptr
;
229 static void check_free_list(void)
231 memory_block
*block_ptr
= free_list_head
;
233 while (block_ptr
!= NULL
) {
234 void *inv_ptr
= (void*)(~(size_t)block_ptr
);
235 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
237 if (memcmp(&block_ptr
->magic
, &inv_ptr
, sizeof(inv_ptr
))) {
238 fprintf(stderr
, "Fatal error: memory corruption detected in front "
239 "of freed pointer %p\n", ptr
);
242 for (i
= 0; i
< block_ptr
->size
; i
++) {
243 if (ptr
[i
] != 0xAA) {
244 fprintf(stderr
, "Fatal error: memory overwriting detected in "
245 "deallocated area: base pointer: %p, offset: %u, data "
246 "written: %02X\n", ptr
, i
, ptr
[i
]);
250 if (memcmp(ptr
+ block_ptr
->size
, &inv_ptr
, sizeof(inv_ptr
))) {
251 fprintf(stderr
, "Fatal error: memory corruption detected at the "
252 "end of freed pointer %p\n", ptr
);
255 block_ptr
= block_ptr
->next
;
258 fprintf(stderr
, "%u deallocated memory block%s OK\n", counter
,
259 counter
> 1 ? "s are" : " is");
262 static void release_free_blocks(void)
264 memory_block
*block_ptr
= free_list_head
;
265 while (block_ptr
!= NULL
) {
266 memory_block
*next_ptr
= block_ptr
->next
;
268 block_ptr
= next_ptr
;
270 free_list_head
= NULL
;
271 free_list_tail
= NULL
;
274 /* MEMORY_DEBUG_FREE */
276 #ifdef MEMORY_DEBUG_ADDRESS
277 /** Check the address and the ordinal of the allocation against the checkpoints
279 * If the address or the ordinal matches, a line is printed to the standard
280 * error. Breakpoints can be set on the printf to trigger when the watched
281 * allocation happens.
283 * @param block_ptr pointer to a memory block structure which is being
284 * allocated/reallocated/freed
285 * @param oper the actual operation: 0=Malloc, 1=Realloc, 2=Free
287 static void check_memory_address(memory_block
*block_ptr
, int oper
)
289 void *ptr
= (unsigned char*)&block_ptr
->begin
;
290 if (ptr
== memory_debug_address
)
292 if (block_ptr
->filename
) {
293 fprintf(stderr
, FILENAME_FORMAT
, block_ptr
->filename
, block_ptr
->lineno
);
295 fprintf(stderr
, "MEMDEBUG: returning pointer %p while %sing memory.\n",
296 ptr
, oper
==0?"allocat":oper
==1?"reallocat":"free");
298 if (block_ptr
->ordinal
== memory_debug_ordinal
) {
299 if (block_ptr
->filename
) {
300 fprintf(stderr
, FILENAME_FORMAT
, block_ptr
->filename
, block_ptr
->lineno
);
302 fprintf(stderr
, "MEMDEBUG: returning ordinal %lu while %sing memory.\n",
303 (unsigned long)block_ptr
->ordinal
,
304 oper
==0 ? "allocat" : (oper
==1 ? "reallocat" : "free"));
308 /* MEMORY_DEBUG_ADDRESS */
310 /*#define FATAL_ERROR_INTERNAL(f,l,s) fatal_error(f,l,s)*/
311 #define MALLOC_INTERNAL(f,l,s) Malloc_dbg(f,l,s)
312 #define MEMPTYSTR_INTERNAL(f,l) memptystr_dbg(f,l)
313 #define MCOPYSTR_INTERNAL(f,l,s) mcopystr_dbg(f,l,s)
314 #define MCOPYSTRN_INTERNAL(f,l,s,l2) mcopystrn_dbg(f,l,s,l2)
315 #define REALLOC_INTERNAL(f,l,p,s) Realloc_dbg(f,l,p,s)
316 #define FREE_INTERNAL(f,l,p) Free_dbg(f,l,p)
317 #define MPRINTF_VA_LIST_INTERNAL(f,l,s,p) mprintf_va_list_dbg(f,l,s,p)
319 static const size_t offset
= (unsigned char*)&(((memory_block
*)NULL
)->begin
)
320 - (unsigned char*)NULL
;
322 static void extract_location(void *p
, const char **fn
, int *ln
)
324 memory_block
*block_ptr
= NULL
;
325 block_ptr
= (memory_block
*)(void*)((unsigned char*)p
- offset
);
326 *fn
= block_ptr
->filename
;
327 *ln
= block_ptr
->lineno
;
331 /* not MEMORY_DEBUG */
333 #define FATAL_ERROR_INTERNAL(f,l,s) fatal_error(s)
334 #define MALLOC_INTERNAL(f,l,s) Malloc(s)
335 #define MEMPTYSTR_INTERNAL(f,l) memptystr()
336 #define MCOPYSTR_INTERNAL(f,l,s) mcopystr(s)
337 #define MCOPYSTRN_INTERNAL(f,l,s,l2) mcopystrn(s,l2)
338 #define REALLOC_INTERNAL(f,l,p,s) Realloc(p,s)
339 #define FREE_INTERNAL(f,l,p) Free(p)
340 #define MPRINTF_VA_LIST_INTERNAL(f,l,s,p) mprintf_va_list(s,p)
342 #define extract_location(p,f,l) ((void)p,(void)f,(void)l)
345 /** Report a fatal error.
347 * @param size the number of bytes that could not be allocated
349 * This function does not return.
351 __attribute__ ((__noreturn__
))
352 static void fatal_error(
354 const char *filename
, int line
,
358 const char *err_msg
= strerror(errno
);
360 fprintf(stderr
, FILENAME_FORMAT
"Fatal error: cannot allocate %lu bytes"
361 " of memory after allocating %lu bytes: ", filename
, line
,
362 (unsigned long) size
, (unsigned long) allocated_size
);
364 fprintf(stderr
, "Fatal error: cannot allocate %lu bytes of memory: ",
365 (unsigned long) size
);
367 if (err_msg
!= NULL
) fprintf(stderr
, "%s. Exiting.\n", err_msg
);
368 else fprintf(stderr
, "Unknown error (errno: %d). Exiting.\n", errno
);
373 void *Malloc(size_t size
)
375 return Malloc_dbg(0,0,size
);
378 void *Malloc_dbg(const char *filename
, int line
, size_t size
)
380 void *Malloc(size_t size
)
386 memory_block
*block_ptr
;
387 block_ptr
= (memory_block
*)malloc(sizeof(*block_ptr
) -
388 sizeof(block_ptr
->begin
) + size
+ sizeof(block_ptr
));
389 if (block_ptr
== NULL
) fatal_error(filename
, line
, size
);
390 block_ptr
->filename
= filename
;
391 block_ptr
->lineno
= line
;
392 block_ptr
->size
= size
;
393 add_to_list(block_ptr
);
394 set_magic_values(block_ptr
);
395 ptr
= &block_ptr
->begin
;
396 total_allocated
+= size
;
397 block_ptr
->ordinal
= alloc_count
++;
398 allocated_size
+= size
;
399 #ifdef MEMORY_DEBUG_ADDRESS
400 check_memory_address(block_ptr
, 0);
402 if (peak_size
< allocated_size
) peak_size
= allocated_size
;
405 if (ptr
== NULL
) fatal_error(size
);
414 void *Realloc(void *ptr
, size_t size
)
416 return Realloc_dbg(0,0,ptr
,size
);
419 void *Realloc_dbg(const char *filename
, int line
, void *ptr
, size_t size
)
421 void *Realloc(void *ptr
, size_t size
)
424 if (ptr
== NULL
) return MALLOC_INTERNAL(filename
, line
, size
);
425 else if (size
== 0) {
426 FREE_INTERNAL(filename
, line
, ptr
);
431 memory_block
*block_ptr
= NULL
;
432 block_ptr
= (memory_block
*)(void*)((unsigned char*)ptr
- offset
);
433 check_magic_values(filename
, line
, block_ptr
, 1);
434 remove_from_list(block_ptr
);
435 allocated_size
-= block_ptr
->size
;
436 if (size
< block_ptr
->size
)
437 memset((unsigned char*)ptr
+ size
, 0x55, block_ptr
->size
- size
);
438 block_ptr
= (memory_block
*)realloc(block_ptr
, sizeof(*block_ptr
) -
439 sizeof(block_ptr
->begin
) + sizeof(block_ptr
) + size
);
440 if (block_ptr
== NULL
) fatal_error(filename
, line
, size
);
441 #ifdef MEMORY_DEBUG_ADDRESS
442 check_memory_address(block_ptr
, 1);
444 block_ptr
->filename
= filename
;
445 block_ptr
->lineno
= line
;
446 block_ptr
->size
= size
;
447 add_to_list(block_ptr
);
448 set_magic_values(block_ptr
);
449 new_ptr
= &block_ptr
->begin
;
450 total_allocated
+= size
;
452 allocated_size
+= size
;
453 if (peak_size
< allocated_size
) peak_size
= allocated_size
;
455 new_ptr
= realloc(ptr
, size
);
456 if (new_ptr
== NULL
) FATAL_ERROR_INTERNAL(filename
, line
, size
);
468 extern void Free_dbg(const char *filename
, int line
, void *ptr
)
475 memory_block
*block_ptr
= NULL
;
476 block_ptr
= (memory_block
*)(void*)((unsigned char*)ptr
- offset
);
477 #ifdef MEMORY_DEBUG_ADDRESS
478 check_memory_address(block_ptr
, 2);
480 check_magic_values(filename
, line
, block_ptr
, 0);
481 remove_from_list(block_ptr
);
482 allocated_size
-= block_ptr
->size
;
483 memset(ptr
, 0xAA, block_ptr
->size
);
484 #ifdef MEMORY_DEBUG_FREE
485 add_to_free_list(block_ptr
);
496 static const size_t maxprint
= 32;
498 void check_mem_leak(const char *program_name
)
501 fprintf(stderr
, "%s(%d): memory usage statistics:\n"
502 "total allocations: %lu\n"
503 "malloc/new calls: %lu\n"
504 "free/delete calls: %lu\n"
505 "peak memory usage: %lu bytes\n"
506 "average block size: %g bytes\n",
507 program_name
, (int)getpid(),
508 (unsigned long)alloc_count
, (unsigned long)malloc_count
,
509 (unsigned long) free_count
, (unsigned long) peak_size
,
510 (double)total_allocated
/ (double)alloc_count
);
511 if (list_head
!= NULL
) {
512 memory_block
*block_ptr
= list_head
;
514 fprintf(stderr
, "unallocated blocks:\n");
516 if (block_ptr
->filename
!= 0) {
517 fprintf(stderr
, FILENAME_FORMAT
,
518 block_ptr
->filename
, block_ptr
->lineno
);
520 fprintf(stderr
, "\tMemory leak at %p, size %lu, ord %lu: ",
521 (void*)&block_ptr
->begin
, (unsigned long)block_ptr
->size
,
522 (unsigned long)block_ptr
->ordinal
);
524 const unsigned char * mm
= (const unsigned char*)&block_ptr
->begin
;
525 size_t x
, limit
= (block_ptr
->size
> maxprint
) ? maxprint
527 for (x
= 0; x
< limit
; ++x
) {
528 fputc( isprint(mm
[x
]) ? mm
[x
] : '.', stderr
);
532 block_ptr
= block_ptr
->next
;
534 } while (block_ptr
!= NULL
);
535 fprintf(stderr
, "total unallocated: %lu bytes in %lu blocks\n",
536 (unsigned long) allocated_size
, (unsigned long) counter
);
538 #ifdef MEMORY_DEBUG_FREE
540 release_free_blocks();
543 if (malloc_count
!= free_count
) {
544 fprintf(stderr
, "%s: warning: memory leakage detected.\n"
545 "Total malloc calls: %lu, free calls: %lu\n"
546 "Please submit a bug report including the current input file(s).\n",
548 (unsigned long) malloc_count
, (unsigned long) free_count
);
554 void check_mem_corrupt(const char *program_name
)
557 memory_block
*block_ptr
;
558 fprintf(stderr
, "%s: checking memory blocks for corruption\n",
560 for (block_ptr
= list_head
; block_ptr
!= NULL
; block_ptr
= block_ptr
->next
)
562 unsigned char *ptr
= (unsigned char*)&block_ptr
->begin
;
563 if (memcmp(ptr
- sizeof(block_ptr
), &block_ptr
, sizeof(block_ptr
))) {
564 fprintf(stderr
, "Fatal error: memory corruption detected in front "
565 "of pointer %p\n", ptr
);
568 if (memcmp(ptr
+ block_ptr
->size
, &block_ptr
, sizeof(block_ptr
))) {
569 fprintf(stderr
, "Fatal error: memory corruption detected at the "
570 "end of pointer %p\n", ptr
);
575 fprintf(stderr
, "%s: %lu memory block%s OK\n", program_name
,
576 (unsigned long) counter
, counter
> 1 ? "s are" : " is");
577 #ifdef MEMORY_DEBUG_FREE
583 /** @brief Find the string length of an expstring_t
585 Finds the length of the C string pointed at by \p str, using some assumptions
586 satisfied by an expstring_t.
588 @pre There is an offset from the beginning of the string which is a power
589 of two, is within the buffer allocated for \p str and it contains '\\0'
590 @pre The allocated buffer is at most twice as long as strlen(str)
591 @pre \p bufsize is a valid pointer
593 @param [in] str an expstring_t, must not be null
594 @param [out] bufsize pointer to a location where the minimum buffer size
595 (always a power of two) is deposited.
596 @return the length of \p str as a C string
598 static size_t fast_strlen(const expstring_t str
, size_t *bufsize
)
600 size_t size
, min
, max
;
601 /* Find the 0 byte at the end of the allocated buffer */
602 for (size
= 1; str
[size
- 1] != '\0'; size
*= 2) {}
604 if (size
== 1) return 0;
605 /* Binary search the second half of the buffer */
608 while (max
- min
> 1) {
609 size_t med
= (min
+ max
) / 2;
610 if (str
[med
] != '\0') min
= med
;
616 /** @brief Find the first power of two which is greater than \p len
618 * @param len the desired length
619 * @return a power of 2 greater than \p len
621 * \p len is taken to be the number of characters needed. The returned value
622 * will always be greater than \p len to accommodate the null terminator.
624 static size_t roundup_size(size_t len
)
627 for (size
= 1; len
>= size
; size
*= 2);
632 expstring_t
mprintf_va_list(const char *fmt
, va_list pvar
)
634 return mprintf_va_list_dbg(0,0,fmt
,pvar
);
637 expstring_t
mprintf_va_list_dbg(const char *filename
, int line
, const char *fmt
, va_list pvar
)
639 expstring_t
mprintf_va_list(const char *fmt
, va_list pvar
)
647 va_copy(pvar2
, pvar
);
648 len
= vsnprintf(buf
, BUFSIZE
, fmt
, pvar2
);
651 /* The result does not fit in buf and we have no idea how many bytes
652 * are needed (only old versions of libc may return -1).
653 * Try to double the buffer size until it is large enough. */
654 for (size
= 2 * BUFSIZE
; ; size
*= 2) {
655 ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
656 va_copy(pvar2
, pvar
);
657 len
= vsnprintf(ptr
, size
, fmt
, pvar2
);
659 if (len
>= 0 && (size_t)len
< size
) break;
660 FREE_INTERNAL(filename
, line
, ptr
);
663 } else if (len
>= BUFSIZE
) {
664 /* The result does not fit in buf, but we know how many bytes we need.
665 * Allocate a buffer that is large enough and repeat vsnprintf() */
667 size
= roundup_size(slen
);
668 ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
669 /* use the original pvar since this is the last try */
670 if (vsnprintf(ptr
, size
, fmt
, pvar
) != len
) {
671 perror("Fatal error: unexpected vsnprintf() return value");
675 /* the complete result is in buf */
677 size
= roundup_size(slen
);
678 ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
679 memcpy(ptr
, buf
, slen
);
681 memset(ptr
+ slen
, '\0', size
- slen
);
686 expstring_t
mprintf_dbg(const char *filename
, int line
, const char *fmt
, ...)
691 ptr
= mprintf_va_list_dbg(filename
, line
, fmt
, pvar
);
697 expstring_t
mprintf(const char *fmt
, ...)
702 ptr
= mprintf_va_list(fmt
, pvar
);
707 /* Tracking the origin: extracts the filename/line from the original allocation
708 * of the expstring_t. */
709 expstring_t
mputprintf_va_list(expstring_t str
, const char *fmt
, va_list pvar
)
711 const char *filename
= NULL
;
715 size_t len
= fast_strlen(str
, &size
);
716 size_t rest
= size
- len
;
719 /* make a copy of pvar to allow re-use later */
720 va_copy(pvar2
, pvar
);
721 len2
= vsnprintf(str
+ len
, rest
, fmt
, pvar2
);
723 extract_location(str
, &filename
, &line
);
725 /* the result does not fit in buf and we have no idea how many
726 * bytes are needed (only old versions of libc may return -1)
727 * try to double the buffer size until it is large enough */
731 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, size
);
733 va_copy(pvar2
, pvar
);
734 len2
= vsnprintf(str
+ len
, rest
, fmt
, pvar2
);
736 } while (len2
< 0 || (size_t)len2
>= rest
);
737 newlen
= len
+ (size_t)len2
;
738 memset(str
+ newlen
, '\0', size
- newlen
);
739 } else if ((size_t)len2
>= rest
) {
740 /* there isn't enough space in buffer, but we know how many bytes
741 * we need: reallocate the buffer to be large enough and repeat
743 size_t newlen
= len
+ (size_t)len2
;
744 size
= roundup_size(newlen
);
745 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, size
);
746 /* use the original pvar since this is the last try */
747 if (vsnprintf(str
+ len
, size
- len
, fmt
, pvar
) != len2
) {
748 perror("Fatal error: unexpected vsnprintf() return value");
751 memset(str
+ newlen
, '\0', size
- newlen
);
753 } else str
= MPRINTF_VA_LIST_INTERNAL(filename
, line
, fmt
, pvar
);
757 expstring_t
mputprintf(expstring_t str
, const char *fmt
, ...)
761 str
= mputprintf_va_list(str
, fmt
, pvar
);
767 expstring_t
memptystr(void)
769 return memptystr_dbg(0,0);
772 expstring_t
memptystr_dbg(const char *filename
, int line
)
774 expstring_t
memptystr(void)
777 expstring_t ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, 1);
783 expstring_t
mcopystr(const char *str
)
785 return mcopystr_dbg(0,0,str
);
788 expstring_t
mcopystr_dbg(const char *filename
, int line
, const char *str
)
790 expstring_t
mcopystr(const char *str
)
794 size_t len
= strlen(str
);
795 size_t size
= roundup_size(len
);
796 expstring_t ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
797 memcpy(ptr
, str
, len
);
798 memset(ptr
+ len
, '\0', size
- len
);
800 } else return MEMPTYSTR_INTERNAL(filename
, line
);
804 expstring_t
mcopystrn(const char *str
, size_t len
)
806 return mcopystrn_dbg(0,0,str
, len
);
809 expstring_t
mcopystrn_dbg(const char *filename
, int line
, const char *str
,
812 expstring_t
mcopystrn(const char *str
, size_t len
)
815 if (len
!= 0 && str
!= NULL
) {
816 size_t size
= roundup_size(len
);
817 expstring_t ptr
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, size
);
818 memcpy(ptr
, str
, len
);
819 memset(ptr
+ len
, '\0', size
- len
);
821 } else return MEMPTYSTR_INTERNAL(filename
, line
);
824 /* Tracking the origin: extracts the filename/line from the original allocation
825 * of the expstring_t. */
826 expstring_t
mputstr(expstring_t str
, const char *str2
)
828 const char *filename
= NULL
;
833 size_t len
= fast_strlen(str
, &size
);
834 size_t len2
= strlen(str2
);
835 size_t newlen
= len
+ len2
;
836 if (size
<= newlen
) {
837 size_t newsize
= roundup_size(newlen
);
838 extract_location(str
, &filename
, &line
);
839 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, newsize
);
840 memset(str
+ newlen
, '\0', newsize
- newlen
);
842 memcpy(str
+ len
, str2
, len2
);
843 } else str
= MCOPYSTR_INTERNAL(filename
, line
, str2
);
848 /* Tracking the origin: extracts the filename/line from the original allocation
849 * of the expstring_t. */
850 expstring_t
mputstrn(expstring_t str
, const char *str2
, size_t len2
)
852 const char *filename
= NULL
;
854 if (len2
!= 0 && str2
!= NULL
) {
857 size_t len
= fast_strlen(str
, &size
);
858 size_t newlen
= len
+ len2
;
859 if (size
<= newlen
) {
860 size_t newsize
= roundup_size(newlen
);
861 extract_location(str
, &filename
, &line
);
862 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, newsize
);
863 memset(str
+ newlen
, '\0', newsize
- newlen
);
865 memcpy(str
+ len
, str2
, len2
);
866 } else str
= MCOPYSTRN_INTERNAL(filename
, line
, str2
, len2
);
871 /* Tracking the origin: extracts the filename/line from the original allocation
872 * of the expstring_t. */
873 expstring_t
mputc(expstring_t str
, char c
)
875 const char *filename
= NULL
;
880 size_t len
= fast_strlen(str
, &size
);
881 if (size
<= len
+ 1) {
882 extract_location(str
, &filename
, &line
);
883 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, 2 * size
);
884 memset(str
+ size
, '\0', size
);
890 str
= (expstring_t
)MALLOC_INTERNAL(filename
, line
, 2);
893 } else str
= MEMPTYSTR_INTERNAL(filename
, line
);
898 /* Tracking the origin: extracts the filename/line from the original allocation
899 * of the expstring_t. */
900 expstring_t
mtruncstr(expstring_t str
, size_t newlen
)
902 const char *filename
= NULL
;
906 size_t len
= fast_strlen(str
, &size
);
908 size_t newsize
= roundup_size(newlen
);
909 if (newsize
< size
) {
910 extract_location(str
, &filename
, &line
);
911 str
= (expstring_t
)REALLOC_INTERNAL(filename
, line
, str
, newsize
);
913 memset(str
+ newlen
, '\0', newsize
- newlen
);
919 size_t mstrlen(const expstring_t str
)
923 return fast_strlen(str
, &size
);
927 char * buildstr(int b
) {
928 if (b
< 0 || b
> 99) return NULL
; /* invalid */
929 if (b
== 99) return memptystr(); /* empty string for full version */
930 return mprintf("%02d", b
);
This page took 0.072759 seconds and 5 git commands to generate.