Skip to content

Commit 1164128

Browse files
committed
Tiny performance and security improvements.
1 parent c97fa66 commit 1164128

3 files changed

Lines changed: 40 additions & 13 deletions

File tree

ChangeLog

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
2026-06-13 Richard Frith-Macdonald <rfm@gnu.org>
2+
3+
* Headers/GNUstepBase/GSObjCRuntime.h:
4+
* Source/GSPrivate.h:
5+
Define a larger size for on-stack memory allocation of buffers, to
6+
reduce the performance overhead of using the heap. Add check for
7+
malloc failure when we do have to allocate buffer space on heap.
8+
19
2026-06-11 Richard Frith-Macdonald <rfm@gnu.org>
210

311
* Source/NSData.m:

Headers/GNUstepBase/GSObjCRuntime.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,13 +532,22 @@ GSLastErrorStr(long error_id) GS_DEPRECATED;
532532

533533

534534

535+
/**
536+
* The maximum number of bytes to allocate from the stack for a butffer.
537+
* For buffer sizes greater than this, we use the heap.
538+
* NB. This MUST be a multiple of 16
539+
*/
540+
#ifndef GS_MAX_BYTES_FROM_STACK
541+
#define GS_MAX_BYTES_FROM_STACK 4096
542+
#endif
543+
535544
#ifndef GS_MAX_OBJECTS_FROM_STACK
536545
/**
537546
* The number of objects to try to get from varargs into an array on
538547
* the stack ... if there are more than this, use the heap.
539548
* NB. This MUST be a multiple of 2
540549
*/
541-
#define GS_MAX_OBJECTS_FROM_STACK 128
550+
#define GS_MAX_OBJECTS_FROM_STACK (GS_MAX_BYTES_FROM_STACK/sizeof(id))
542551
#endif
543552

544553
/**

Source/GSPrivate.h

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,16 @@ typedef struct objc_category* Category;
9090

9191
#import "Foundation/NSString.h"
9292

93+
/** Macro to call malloc() to allocate memory from the heap for N items of
94+
* type T. If the call to malloc() fails, this raises an exception reporting
95+
* the number and size of the items requested.
96+
*/
97+
#define GS_MALLOC(N, T) \
98+
((T*)malloc((N) * sizeof(T)) ?: (\
99+
[NSException raise: NSInternalInconsistencyException\
100+
format: @"Failed to create buffer for %lu items of size %u",\
101+
(unsigned long)(N), (unsigned)sizeof(T)], __builtin_unreachable(), (T*)0))
102+
93103
/**
94104
* Macro to manage memory for chunks of code that need to work with
95105
* arrays of items. Use this to start the block of code using
@@ -108,36 +118,36 @@ __attribute__((unused)) static void GSFreeTempBuffer(void **b)
108118
}
109119
# define GS_BEGINITEMBUF(P, S, T) { \
110120
unsigned _ilen = (S) > 0 ? (S) : 1; \
111-
T _ibuf[_ilen <= GS_MAX_OBJECTS_FROM_STACK ? _ilen : 1]; \
121+
T _ibuf[_ilen <= GS_MAX_BYTES_FROM_STACK/sizeof(T) ? _ilen : 1]; \
112122
T *P = _ibuf;\
113123
__attribute__((cleanup(GSFreeTempBuffer))) void *_base = 0;\
114-
if (_ilen > GS_MAX_OBJECTS_FROM_STACK)\
124+
if (_ilen > GS_MAX_BYTES_FROM_STACK/sizeof(T))\
115125
{\
116-
_base = malloc(_ilen * sizeof(T));\
126+
_base = GS_MALLOC(_ilen, T);\
117127
P = _base;\
118128
}
119129
# define GS_BEGINITEMBUF2(P, S, T) { \
120130
unsigned _ilen2 = (S) > 0 ? (S) : 1; \
121-
T _ibuf2[_ilen2 <= GS_MAX_OBJECTS_FROM_STACK ? _ilen2 : 1]; \
131+
T _ibuf2[_ilen2 <= GS_MAX_BYTES_FROM_STACK/sizeof(T) ? _ilen2 : 1]; \
122132
T *P = _ibuf2;\
123133
__attribute__((cleanup(GSFreeTempBuffer))) void *_base2 = 0;\
124-
if (_ilen2 > GS_MAX_OBJECTS_FROM_STACK)\
134+
if (_ilen2 > GS_MAX_BYTES_FROM_STACK/sizeof(T))\
125135
{\
126-
_base2 = malloc(_ilen2 * sizeof(T));\
136+
_base2 = GS_MALLOC(_ilen2, T);\
127137
P = _base2;\
128138
}
129139
#else
130140
# define GS_BEGINITEMBUF(P, S, T) { \
131141
unsigned _ilen = (S) > 0 ? (S) : 1; \
132-
T _ibuf[_ilen <= GS_MAX_OBJECTS_FROM_STACK ? _ilen : 1]; \
133-
T *_base = (_ilen <= GS_MAX_OBJECTS_FROM_STACK) ? _ibuf \
134-
: (T*)malloc(_ilen * sizeof(T)); \
142+
T _ibuf[_ilen <= GS_MAX_BYTES_FROM_STACK/sizeof(T) ? _ilen : 1]; \
143+
T *_base = (_ilen <= GS_MAX_BYTES_FROM_STACK/sizeof(T)) ? _ibuf \
144+
: GS_MALLOC(_ilen, T); \
135145
T *(P) = _base;
136146
# define GS_BEGINITEMBUF2(P, S, T) { \
137147
unsigned _ilen2 = (S) > 0 ? (S) : 1; \
138-
T _ibuf2[_ilen2 <= GS_MAX_OBJECTS_FROM_STACK ? _ilen2 : 1]; \
139-
T *_base2 = (_ilen2 <= GS_MAX_OBJECTS_FROM_STACK) ? _ibuf2 \
140-
: (T*)malloc(_ilen2 * sizeof(T)); \
148+
T _ibuf2[_ilen2 <= GS_MAX_BYTES_FROM_STACK/sizeof(T) ? _ilen2 : 1]; \
149+
T *_base2 = (_ilen2 <= GS_MAX_BYTES_FROM_STACK/sizeof(T)) ? _ibuf2 \
150+
: GS_MALLOC(_ilen2, T); \
141151
T *(P) = _base2;
142152
#endif
143153

0 commit comments

Comments
 (0)