@@ -22,61 +22,81 @@ MRB_END_DECL
2222
2323#include < mruby/cpp_helpers.hpp>
2424#include < mruby/num_helpers.hpp>
25+ #include < mruby/branch_pred.h>
2526#include < cstring>
2627
2728#include < string>
2829#include < string_view>
2930#include < atomic>
3031#include < cstdint>
3132
32- #if ((defined(__has_builtin) && __has_builtin(__builtin_expect))||(__GNUC__ >= 3) || (__INTEL_COMPILER >= 800) || defined(__clang__))
33- #define likely (x ) __builtin_expect(!!(x), 1 )
34- #define unlikely (x ) __builtin_expect(!!(x), 0 )
35- #else
36- #define likely (x ) (x)
37- #define unlikely (x ) (x)
38- #endif
3933
4034/* ------------------------------------------------------------------------
4135 * SBO writer
4236 * ------------------------------------------------------------------------ */
37+ static mrb_int
38+ safe_size_to_mrb_int (mrb_state *mrb, size_t sz)
39+ {
40+ if (unlikely (sz > (size_t )MRB_INT_MAX)) {
41+ mrb_raise (mrb, E_ARGUMENT_ERROR, " msgpack: size too large" );
42+ }
43+ return (mrb_int)sz;
44+ }
45+
46+ mrb_int
47+ compute_capacity (mrb_state *mrb, size_t stack_size, size_t buf_size)
48+ {
49+ mrb_int s = safe_size_to_mrb_int (mrb, stack_size);
50+ mrb_int b = safe_size_to_mrb_int (mrb, buf_size);
51+
52+ mrb_int sum;
53+ if (unlikely (mrb_int_add_overflow (s, b, &sum))) {
54+ mrb_raise (mrb, E_ARGUMENT_ERROR, " msgpack: size overflow" );
55+ }
56+
57+ mrb_int capa;
58+ if (unlikely (mrb_int_mul_overflow (sum, 2 , &capa))) {
59+ mrb_raise (mrb, E_ARGUMENT_ERROR, " msgpack: size overflow" );
60+ }
61+
62+ return capa;
63+ }
4364
4465struct mrb_msgpack_sbo_writer {
4566 mrb_msgpack_sbo_writer (mrb_state* mrb)
46- : mrb(mrb), heap_str(mrb_nil_value()) {}
47-
48- void write (const char * buf, size_t len) {
49- if (!using_heap) {
50- if (len <= STACK_CAP - size) {
51- std::memcpy (stack_buf + size, buf, len);
52- size += len;
53- return ;
67+ : mrb(mrb) {}
68+
69+ void write (const char * buf, size_t buf_size) {
70+ if (mrb_string_p (heap_str)) {
71+ mrb_str_cat (mrb, heap_str, buf, buf_size);
72+ } else {
73+ if (likely (buf_size <= STACK_CAP - stack_size)) {
74+ std::memcpy (stack_buf + stack_size, buf, buf_size);
75+ stack_size += buf_size;
76+ } else {
77+ mrb_int capa = compute_capacity (mrb, stack_size, buf_size);
78+ heap_str = mrb_str_new_capa (mrb, capa);
79+ mrb_str_cat (mrb, heap_str, stack_buf, stack_size);
80+ mrb_str_cat (mrb, heap_str, buf, buf_size);
5481 }
55-
56- using_heap = true ;
57- heap_str = mrb_str_new_capa (mrb, (mrb_int)(size + len) * 2 );
58- mrb_str_cat (mrb, heap_str, stack_buf, size);
5982 }
60-
61- mrb_str_cat (mrb, heap_str, buf, len);
6283 }
6384
6485 mrb_value result () {
65- if (!using_heap) {
66- return mrb_str_new (mrb, stack_buf, size);
86+ if (mrb_string_p (heap_str)) {
87+ return heap_str;
88+ } else {
89+ return mrb_str_new (mrb, stack_buf, stack_size);
6790 }
68- return heap_str;
6991 }
7092
7193private:
7294 mrb_state* mrb;
7395
7496 static constexpr size_t STACK_CAP = 8 * 1024 ;
7597 char stack_buf[STACK_CAP];
76- size_t size = 0 ;
77- bool using_heap = false ;
78-
79- mrb_value heap_str;
98+ size_t stack_size = 0 ;
99+ mrb_value heap_str = mrb_undef_value();
80100};
81101
82102/* ------------------------------------------------------------------------
@@ -120,7 +140,7 @@ static mrb_value
120140ensure_ext_registry (mrb_state *mrb)
121141{
122142 mrb_value reg = mrb_gv_get (mrb, MRB_SYM (__msgpack_ext_registry__));
123- if (! mrb_nil_p (reg)) return reg;
143+ if (mrb_hash_p (reg)) return reg;
124144
125145 mrb_value registry = mrb_hash_new (mrb);
126146 mrb_value packers = mrb_hash_new (mrb);
@@ -137,7 +157,7 @@ static mrb_value
137157ensure_msgpack_ctx (mrb_state *mrb)
138158{
139159 mrb_value ctxv = mrb_gv_get (mrb, MRB_SYM (__msgpack__ctx));
140- if (! mrb_nil_p (ctxv)) return ctxv;
160+ if (mrb_cptr_p (ctxv)) return ctxv;
141161
142162 /* Allocate the C context directly and store as a cptr in a GV.
143163 This avoids creating any Ruby classes/modules and works with mrb_open_core. */
0 commit comments