• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 10774454435

09 Sep 2024 01:39PM UTC coverage: 92.806% (-0.08%) from 92.882%
10774454435

push

github

Buristan
FFI: Drop finalizer table rehash after GC cycle.

Reported by Sergey Kaplun.

(cherry picked from commit fb22d0f80)

The raising of the OOM error when rehashing the finalizer table (when we
can't allocate a new hash part) leads to crashes in either
`lj_trace_exit()` or `lj_trace_unwind()` due to unprotected error
raising, which either has no DWARF eh_frame [1] or loses the context of
the JIT compiler.

This patch drops rehashing of the cdata finalizer table to avoid these
crashes. It will prevent the cdata finalizer table from shrinking when a
huge amount of the cdata objects is collected by the GC. OTOH, the
finzlizer table most probably will grow anyway to the old size, so this
is not crucial.

Sergey Kaplun:
* added the description and the test for the problem

[1]: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html

Part of tarantool/tarantool#10199
Resolves tarantool/tarantool#10290

5681 of 6025 branches covered (94.29%)

Branch coverage included in aggregate %.

21655 of 23430 relevant lines covered (92.42%)

2945096.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

13.79
/src/lj_utils_leb128.c
1
/*
2
** Working with LEB128/ULEB128 encoding.
3
**
4
** Major portions taken verbatim or adapted from the LuaVela.
5
** Copyright (C) 2015-2019 IPONWEB Ltd.
6
*/
7

8
#define lj_utils_leb128_c
9
#define LUA_CORE
10

11
#include "lj_utils.h"
12
#include "lj_obj.h"
13

14
#define LINK_BIT          (0x80)
15
#define MIN_TWOBYTE_VALUE (0x80)
16
#define PAYLOAD_MASK      (0x7f)
17
#define SHIFT_STEP        (7)
18
#define LEB_SIGN_BIT      (0x40)
19

20
/* ------------------------- Reading LEB128/ULEB128 ------------------------- */
21

22
/*
23
** XXX: For each LEB128 type (signed/unsigned) we have two versions of read
24
** functions: The one consuming unlimited number of input octets and the one
25
** consuming not more than given number of input octets. Currently reading
26
** is not used in performance critical places, so these two functions are
27
** implemented via single low-level function + run-time mode check. Feel free
28
** to change if this becomes a bottleneck.
29
*/
30

31
static LJ_AINLINE size_t _read_leb128(int64_t *out, const uint8_t *buffer,
×
32
                                      size_t n)
33
{
34
  size_t i = 0;
×
35
  uint64_t shift = 0;
×
36
  int64_t value = 0;
×
37
  uint8_t octet;
×
38

39
  for(;;) {
×
40
    if (n != 0 && i + 1 > n)
×
41
      return 0;
42
    octet = buffer[i++];
×
43
    value |= ((int64_t)(octet & PAYLOAD_MASK)) << shift;
×
44
    shift += SHIFT_STEP;
×
45
    if (!(octet & LINK_BIT))
×
46
      break;
47
  }
48

49
  if (octet & LEB_SIGN_BIT && shift < sizeof(int64_t) * 8)
×
50
    value |= -(1 << shift);
×
51

52
  *out = value;
×
53
  return i;
×
54
}
55

56
size_t LJ_FASTCALL lj_utils_read_leb128(int64_t *out, const uint8_t *buffer)
×
57
{
58
  return _read_leb128(out, buffer, 0);
×
59
}
60

61
size_t LJ_FASTCALL lj_utils_read_leb128_n(int64_t *out, const uint8_t *buffer,
×
62
                                          size_t n)
63
{
64
  return _read_leb128(out, buffer, n);
×
65
}
66

67

68
static LJ_AINLINE size_t _read_uleb128(uint64_t *out, const uint8_t *buffer,
×
69
                                       size_t n)
70
{
71
  size_t i = 0;
×
72
  uint64_t value = 0;
×
73
  uint64_t shift = 0;
×
74
  uint8_t octet;
×
75

76
  for(;;) {
×
77
    if (n != 0 && i + 1 > n)
×
78
      return 0;
79
    octet = buffer[i++];
×
80
    value |= ((uint64_t)(octet & PAYLOAD_MASK)) << shift;
×
81
    shift += SHIFT_STEP;
×
82
    if (!(octet & LINK_BIT))
×
83
      break;
84
  }
85

86
  *out = value;
×
87
  return i;
×
88
}
89

90
size_t LJ_FASTCALL lj_utils_read_uleb128(uint64_t *out, const uint8_t *buffer)
×
91
{
92
  return _read_uleb128(out, buffer, 0);
×
93
}
94

95
size_t LJ_FASTCALL lj_utils_read_uleb128_n(uint64_t *out, const uint8_t *buffer,
×
96
                                           size_t n)
97
{
98
  return _read_uleb128(out, buffer, n);
×
99
}
100

101
/* ------------------------- Writing LEB128/ULEB128 ------------------------- */
102

103
size_t LJ_FASTCALL lj_utils_write_leb128(uint8_t *buffer, int64_t value)
×
104
{
105
  size_t i = 0;
×
106

107
  /* LEB_SIGN_BIT propagation to check the remaining value. */
108
  while ((uint64_t)(value + LEB_SIGN_BIT) >= MIN_TWOBYTE_VALUE) {
×
109
    buffer[i++] = (uint8_t)((value & PAYLOAD_MASK) | LINK_BIT);
×
110
    value >>= SHIFT_STEP;
×
111
  }
112

113
  /* Omit LINK_BIT in case of overflow. */
114
  buffer[i++] = (uint8_t)(value & PAYLOAD_MASK);
×
115

116
  lj_assertX(i <= LEB128_U64_MAXSIZE, "bad leb128 size");
×
117

118
  return i;
×
119
}
120

121
size_t LJ_FASTCALL lj_utils_write_uleb128(uint8_t *buffer, uint64_t value)
1,110,044✔
122
{
123
  size_t i = 0;
1,110,044✔
124

125
  for (; value >= MIN_TWOBYTE_VALUE; value >>= SHIFT_STEP)
4,441,659✔
126
    buffer[i++] = (uint8_t)((value & PAYLOAD_MASK) | LINK_BIT);
3,331,615✔
127

128
  buffer[i++] = (uint8_t)value;
1,110,044✔
129

130
  lj_assertX(i <= LEB128_U64_MAXSIZE, "bad uleb128 size");
1,110,044✔
131

132
  return i;
1,110,044✔
133
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc