Coverage Report

Created: 2026-07-16 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tdengine/source/os/src/osMemory.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15
16
#define ALLOW_FORBID_FUNC
17
#ifdef _TD_DARWIN_64
18
#include <malloc/malloc.h>
19
#else
20
#include <malloc.h>
21
#endif
22
#include "os.h"
23
#include "tdef.h"
24
25
int32_t          tsRandErrChance = 1;
26
int64_t          tsRandErrDivisor = 10001;
27
int64_t          tsRandErrScope = (RAND_ERR_MEMORY | RAND_ERR_FILE | RAND_ERR_NETWORK);
28
threadlocal bool tsEnableRandErr = 0;
29
30
#if defined(USE_TD_MEMORY) || defined(USE_ADDR2LINE)
31
32
#define TD_MEMORY_SYMBOL ('T' << 24 | 'A' << 16 | 'O' << 8 | 'S')
33
34
#define TD_MEMORY_STACK_TRACE_DEPTH 10
35
36
typedef struct TdMemoryInfo *TdMemoryInfoPtr;
37
38
typedef struct TdMemoryInfo {
39
  int32_t symbol;
40
  int32_t memorySize;
41
  void   *stackTrace[TD_MEMORY_STACK_TRACE_DEPTH];  // gdb: disassemble /m 0xXXX
42
  // TdMemoryInfoPtr pNext;
43
  // TdMemoryInfoPtr pPrev;
44
} TdMemoryInfo;
45
46
// static TdMemoryInfoPtr GlobalMemoryPtr = NULL;
47
48
#ifdef WINDOWS
49
#define tstrdup(str) _strdup(str)
50
51
int32_t taosBackTrace(void **buffer, int32_t size) {
52
  int32_t frame = 0;
53
  return frame;
54
}
55
56
#ifdef USE_ADDR2LINE
57
#include <DbgHelp.h>
58
#pragma comment(lib, "dbghelp.lib")
59
60
void taosPrintBackTrace() {
61
#define MAX_STACK_FRAMES 20
62
63
  void *pStack[MAX_STACK_FRAMES];
64
65
  HANDLE process = GetCurrentProcess();
66
  SymInitialize(process, NULL, TRUE);
67
  WORD frames = CaptureStackBackTrace(1, MAX_STACK_FRAMES, pStack, NULL);
68
69
  char buf_tmp[1024];
70
  for (WORD i = 0; i < frames; ++i) {
71
    DWORD64 address = (DWORD64)(pStack[i]);
72
73
    DWORD64      displacementSym = 0;
74
    char         buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
75
    PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
76
    pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
77
    pSymbol->MaxNameLen = MAX_SYM_NAME;
78
79
    DWORD           displacementLine = 0;
80
    IMAGEHLP_LINE64 line;
81
    // SymSetOptions(SYMOPT_LOAD_LINES);
82
    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
83
84
    if (SymFromAddr(process, address, &displacementSym, pSymbol) &&
85
        SymGetLineFromAddr64(process, address, &displacementLine, &line)) {
86
      snprintf(buf_tmp, sizeof(buf_tmp), "BackTrace %08" PRId64 " %s:%d %s\n", taosGetSelfPthreadId(), line.FileName,
87
               line.LineNumber, pSymbol->Name);
88
    } else {
89
      snprintf(buf_tmp, sizeof(buf_tmp), "BackTrace error: %d\n", GetLastError());
90
    }
91
    write(1, buf_tmp, strlen(buf_tmp));
92
  }
93
}
94
#endif
95
#else
96
#define tstrdup(str) strdup(str)
97
98
#include <execinfo.h>
99
100
#define STACKCALL __attribute__((regparm(1), noinline))
101
void **STACKCALL taosGetEbp(void) {
102
  void **ebp = NULL;
103
  __asm__ __volatile__("mov %%rbp, %0;\n\t"
104
                       : "=m"(ebp)  /* output */
105
                       :            /* input */
106
                       : "memory"); /* not affect register */
107
  return (void **)(*ebp);
108
}
109
110
int32_t taosBackTrace(void **buffer, int32_t size) {
111
  int32_t frame = 0;
112
  void  **ebp;
113
  void  **ret = NULL;
114
  size_t  func_frame_distance = 0;
115
  if (buffer != NULL && size > 0) {
116
    ebp = taosGetEbp();
117
    func_frame_distance = (size_t)*ebp - (size_t)ebp;
118
    while (ebp && frame < size && (func_frame_distance < (1ULL << 24))  // assume function ebp more than 16M
119
           && (func_frame_distance > 0)) {
120
      ret = ebp + 1;
121
      buffer[frame++] = *ret;
122
      ebp = (void **)(*ebp);
123
      func_frame_distance = (size_t)*ebp - (size_t)ebp;
124
    }
125
  }
126
  return frame;
127
}
128
129
// char **taosBackTraceSymbols(int32_t *size) {
130
//   void  *buffer[20] = {NULL};
131
//   *size = taosBackTrace(buffer, 20);
132
//   return backtrace_symbols(buffer, *size);
133
// }
134
135
#ifdef USE_ADDR2LINE
136
137
#include "dwarf.h"
138
#include "libdwarf.h"
139
#include "osThread.h"
140
141
#define DW_PR_DUu "llu"
142
143
typedef struct lookup_table {
144
  Dwarf_Line         *table;
145
  Dwarf_Line_Context *ctxts;
146
  int                 cnt;
147
  Dwarf_Addr          low;
148
  Dwarf_Addr          high;
149
} lookup_tableT;
150
151
extern int  create_lookup_table(Dwarf_Debug dbg, lookup_tableT *lookup_table);
152
extern void delete_lookup_table(lookup_tableT *lookup_table);
153
154
size_t              addr = 0;
155
lookup_tableT       lookup_table;
156
Dwarf_Debug         tDbg;
157
static TdThreadOnce traceThreadInit = PTHREAD_ONCE_INIT;
158
159
void endTrace() {
160
  TdThreadOnce tmp = PTHREAD_ONCE_INIT;
161
  if (memcmp(&traceThreadInit, &tmp, sizeof(TdThreadOnce)) != 0) {
162
    delete_lookup_table(&lookup_table);
163
    dwarf_finish(tDbg);
164
  }
165
}
166
void startTrace() {
167
  int       ret;
168
  Dwarf_Ptr errarg = 0;
169
170
  FILE *fp = fopen("/proc/self/maps", "r");
171
  ret = fscanf(fp, "%lx-", &addr);
172
  fclose(fp);
173
174
  ret = dwarf_init_path("/proc/self/exe", NULL, 0, DW_GROUPNUMBER_ANY, NULL, errarg, &tDbg, NULL);
175
  if (ret == DW_DLV_NO_ENTRY) {
176
    printf("Unable to open file");
177
    return;
178
  }
179
180
  ret = create_lookup_table(tDbg, &lookup_table);
181
  if (ret != DW_DLV_OK) {
182
    printf("Unable to create lookup table");
183
    return;
184
  }
185
  atexit(endTrace);
186
}
187
static void print_line(Dwarf_Debug dbg, Dwarf_Line line, Dwarf_Addr pc) {
188
  char          *linesrc = "??";
189
  Dwarf_Unsigned lineno = 0;
190
191
  if (line) {
192
    dwarf_linesrc(line, &linesrc, NULL);
193
    dwarf_lineno(line, &lineno, NULL);
194
  }
195
  (void)printf("BackTrace %08" PRId64 " %s:%" DW_PR_DUu "\n", taosGetSelfPthreadId(), linesrc, lineno);
196
  if (line) dwarf_dealloc(dbg, linesrc, DW_DLA_STRING);
197
}
198
void taosPrintBackTrace() {
199
  int        size = 20;
200
  void     **buffer[20];
201
  Dwarf_Addr pc;
202
  int32_t    frame = 0;
203
  void     **ebp;
204
  void     **ret = NULL;
205
  size_t     func_frame_distance = 0;
206
207
  taosThreadOnce(&traceThreadInit, startTrace);
208
209
  if (buffer != NULL && size > 0) {
210
    ebp = taosGetEbp();
211
    func_frame_distance = (size_t)*ebp - (size_t)ebp;
212
    while (ebp && frame < size && (func_frame_distance < (1ULL << 24)) && (func_frame_distance > 0)) {
213
      ret = ebp + 1;
214
      buffer[frame++] = *ret;
215
      ebp = (void **)(*ebp);
216
      func_frame_distance = (size_t)*ebp - (size_t)ebp;
217
    }
218
    for (size_t i = 0; i < frame; i++) {
219
      pc = (size_t)buffer[i] - addr;
220
      if (pc > 0) {
221
        if (pc >= lookup_table.low && pc < lookup_table.high) {
222
          Dwarf_Line line = lookup_table.table[pc - lookup_table.low];
223
          if (line) print_line(tDbg, line, pc);
224
        }
225
      }
226
    }
227
  }
228
}
229
#endif
230
#endif
231
#endif
232
233
#ifndef USE_ADDR2LINE
234
0
void taosPrintBackTrace() { return; }
235
#endif
236
237
0
int32_t taosMemoryDbgInit() {
238
0
#if defined(LINUX) && !defined(_ALPINE) && !defined(TD_ASTRA)
239
0
  int ret = mallopt(M_MMAP_THRESHOLD, 0);
240
0
  if (0 == ret) {
241
0
    return TAOS_SYSTEM_ERROR(ERRNO);
242
0
  }
243
244
0
  return 0;
245
#else
246
  return TSDB_CODE_FAILED;
247
#endif
248
0
}
249
250
0
int32_t taosMemoryDbgInitRestore() {
251
0
#if defined(LINUX) && !defined(_ALPINE) && !defined(TD_ASTRA)
252
0
  int ret = mallopt(M_MMAP_THRESHOLD, 128 * 1024);
253
0
  if (0 == ret) {
254
0
    return TAOS_SYSTEM_ERROR(ERRNO);
255
0
  }
256
257
0
  return 0;
258
#else
259
  return TSDB_CODE_FAILED;
260
#endif
261
0
}
262
263
404k
void *taosMemMalloc(int64_t size) {
264
#ifdef USE_TD_MEMORY
265
  void *tmp = malloc(size + sizeof(TdMemoryInfo));
266
  if (tmp == NULL) return NULL;
267
268
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)tmp;
269
  pTdMemoryInfo->memorySize = size;
270
  pTdMemoryInfo->symbol = TD_MEMORY_SYMBOL;
271
  taosBackTrace(pTdMemoryInfo->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
272
273
  return (char *)tmp + sizeof(TdMemoryInfo);
274
#else
275
276
#ifdef BUILD_WITH_RAND_ERR
277
  if (tsEnableRandErr && (tsRandErrScope & RAND_ERR_MEMORY)) {
278
    uint32_t r = taosRand() % tsRandErrDivisor;
279
    if ((r + 1) <= tsRandErrChance) {
280
      terrno = TSDB_CODE_OUT_OF_MEMORY;
281
      return NULL;
282
    }
283
  }
284
#endif
285
#ifdef TD_ASTRA
286
  if (size == 0) size = 1;
287
#endif
288
404k
  void *p = malloc(size);
289
404k
  if (NULL == p) {
290
0
    terrno = TSDB_CODE_OUT_OF_MEMORY;
291
0
  }
292
404k
  return p;
293
404k
#endif
294
404k
}
295
296
2.53M
void *taosMemCalloc(int64_t num, int64_t size) {
297
#ifdef USE_TD_MEMORY
298
  int32_t memorySize = num * size;
299
  char   *tmp = calloc(memorySize + sizeof(TdMemoryInfo), 1);
300
  if (tmp == NULL) {
301
    terrno = TSDB_CODE_OUT_OF_MEMORY;
302
    return NULL;
303
  }
304
305
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)tmp;
306
  pTdMemoryInfo->memorySize = memorySize;
307
  pTdMemoryInfo->symbol = TD_MEMORY_SYMBOL;
308
  taosBackTrace(pTdMemoryInfo->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
309
310
  return (char *)tmp + sizeof(TdMemoryInfo);
311
#else
312
#ifdef BUILD_WITH_RAND_ERR
313
  if (tsEnableRandErr && (tsRandErrScope & RAND_ERR_MEMORY)) {
314
    uint32_t r = taosRand() % tsRandErrDivisor;
315
    if ((r + 1) <= tsRandErrChance) {
316
      terrno = TSDB_CODE_OUT_OF_MEMORY;
317
      uError("random memory error: %s, %s", tstrerror(terrno), __func__);
318
      return NULL;
319
    }
320
  }
321
#endif
322
#ifdef TD_ASTRA
323
  if (0 == num || 0 == size) num = size = 1; 
324
#endif
325
2.53M
  void *p = calloc(num, size);
326
2.53M
  if (NULL == p) {
327
0
    terrno = TSDB_CODE_OUT_OF_MEMORY;
328
0
  }
329
2.53M
  return p;
330
2.53M
#endif
331
2.53M
}
332
333
1.99k
void *taosMemRealloc(void *ptr, int64_t size) {
334
#ifdef USE_TD_MEMORY
335
  if (ptr == NULL) return taosMemoryMalloc(size);
336
337
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
338
  if (tpTdMemoryInfo->symbol != TD_MEMORY_SYMBOL) {
339
    terrno = TSDB_CODE_OUT_OF_MEMORY;
340
    return NULL;
341
  }
342
343
  TdMemoryInfo tdMemoryInfo;
344
  memcpy(&tdMemoryInfo, pTdMemoryInfo, sizeof(TdMemoryInfo));
345
346
  void *tmp = realloc(pTdMemoryInfo, size + sizeof(TdMemoryInfo));
347
  if (tmp == NULL) {
348
    terrno = TSDB_CODE_OUT_OF_MEMORY;
349
    return NULL;
350
  }
351
352
  memcpy(tmp, &tdMemoryInfo, sizeof(TdMemoryInfo));
353
  ((TdMemoryInfoPtr)tmp)->memorySize = size;
354
355
  return (char *)tmp + sizeof(TdMemoryInfo);
356
#else
357
#ifdef BUILD_WITH_RAND_ERR
358
  if (tsEnableRandErr && (tsRandErrScope & RAND_ERR_MEMORY)) {
359
    uint32_t r = taosRand() % tsRandErrDivisor;
360
    if ((r + 1) <= tsRandErrChance) {
361
      terrno = TSDB_CODE_OUT_OF_MEMORY;
362
      return NULL;
363
    }
364
  }
365
#endif
366
#ifdef TD_ASTRA
367
  if (size == 0) size = 1;
368
#endif
369
1.99k
  void *p = realloc(ptr, size);
370
1.99k
  if (size > 0 && NULL == p) {
371
0
    terrno = TSDB_CODE_OUT_OF_MEMORY;
372
0
  }
373
1.99k
  return p;
374
1.99k
#endif
375
1.99k
}
376
377
211k
char *taosStrdupi(const char *ptr) {
378
#ifdef USE_TD_MEMORY
379
  if (ptr == NULL) return NULL;
380
381
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
382
  if (pTdMemoryInfo->symbol != TD_MEMORY_SYMBOL) {
383
    return NULL;
384
  }
385
  void *tmp = tstrdup(pTdMemoryInfo);
386
  if (tmp == NULL) return NULL;
387
388
  memcpy(tmp, pTdMemoryInfo, sizeof(TdMemoryInfo));
389
  taosBackTrace(((TdMemoryInfoPtr)tmp)->stackTrace, TD_MEMORY_STACK_TRACE_DEPTH);
390
391
  return (char *)tmp + sizeof(TdMemoryInfo);
392
#else
393
#ifdef BUILD_WITH_RAND_ERR
394
  if (tsEnableRandErr && (tsRandErrScope & RAND_ERR_MEMORY)) {
395
    uint32_t r = taosRand() % tsRandErrDivisor;
396
    if ((r + 1) <= tsRandErrChance) {
397
      terrno = TSDB_CODE_OUT_OF_MEMORY;
398
      return NULL;
399
    }
400
  }
401
#endif
402
403
211k
  return tstrdup(ptr);
404
211k
#endif
405
211k
}
406
407
408
3.12M
void taosMemFree(void *ptr) {
409
3.12M
  if (NULL == ptr) return;
410
#ifdef USE_TD_MEMORY
411
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
412
  if (pTdMemoryInfo->symbol == TD_MEMORY_SYMBOL) {
413
    pTdMemoryInfo->memorySize = 0;
414
    // memset(pTdMemoryInfo, 0, sizeof(TdMemoryInfo));
415
    free(pTdMemoryInfo);
416
  } else {
417
    free(ptr);
418
  }
419
#else
420
3.12M
  return free(ptr);
421
3.12M
#endif
422
3.12M
}
423
424
0
int64_t taosMemSize(void *ptr) {
425
0
  if (ptr == NULL) return 0;
426
427
#ifdef USE_TD_MEMORY
428
  TdMemoryInfoPtr pTdMemoryInfo = (TdMemoryInfoPtr)((char *)ptr - sizeof(TdMemoryInfo));
429
  if (pTdMemoryInfo->symbol != TD_MEMORY_SYMBOL) {
430
    return NULL;
431
  }
432
433
  return pTdMemoryInfo->memorySize;
434
#else
435
#ifdef WINDOWS
436
  return _msize(ptr);
437
#elif defined(_TD_DARWIN_64)
438
  return malloc_size(ptr);
439
#elif defined(TD_ASTRA)
440
  return 0;  // TD_ASTRA_TODO N/A
441
#else
442
0
  return malloc_usable_size(ptr);
443
0
#endif
444
0
#endif
445
0
}
446
447
0
int32_t taosMemTrim(int32_t size, bool* trimed) {
448
#if defined(WINDOWS) || defined(DARWIN) || defined(_ALPINE) || defined(TD_ASTRA)
449
  // do nothing
450
  return TSDB_CODE_SUCCESS;
451
#else
452
0
  if (trimed) {
453
0
    *trimed = malloc_trim(size);
454
0
  } else {
455
0
    TAOS_UNUSED(malloc_trim(size));
456
0
  }
457
  
458
0
  return TSDB_CODE_SUCCESS;
459
0
#endif
460
0
}
461
462
0
void *taosMemMallocAlign(uint32_t alignment, int64_t size) {
463
#ifdef USE_TD_MEMORY
464
  return NULL;
465
#else
466
0
#if defined(LINUX)
467
#ifdef BUILD_WITH_RAND_ERR
468
  if (tsEnableRandErr && (tsRandErrScope & RAND_ERR_MEMORY)) {
469
    uint32_t r = taosRand() % tsRandErrDivisor;
470
    if ((r + 1) <= tsRandErrChance) {
471
      terrno = TSDB_CODE_OUT_OF_MEMORY;
472
      return NULL;
473
    }
474
  }
475
#endif
476
477
0
  void *p = memalign(alignment, size);
478
0
  if (NULL == p) {
479
0
    if (ENOMEM == ERRNO) {
480
0
      terrno = TSDB_CODE_OUT_OF_MEMORY;
481
0
    } else {
482
0
      terrno = TAOS_SYSTEM_ERROR(ERRNO);
483
0
    }
484
0
  }
485
0
  return p;
486
#else
487
  return taosMemMalloc(size);
488
#endif
489
0
#endif
490
0
}