[ruby/json] fbuffer.c: add debug mode with bound checks.
This would have caught https://github.com/ruby/json/pull/808 on CI. https://github.com/ruby/json/commit/8109421fb4
This commit is contained in:
parent
f171a263f7
commit
212213a552
@ -36,6 +36,12 @@ typedef unsigned char _Bool;
|
||||
# define MAYBE_UNUSED(x) x
|
||||
#endif
|
||||
|
||||
#ifdef RUBY_DEBUG
|
||||
#ifndef JSON_DEBUG
|
||||
#define JSON_DEBUG RUBY_DEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum fbuffer_type {
|
||||
FBUFFER_HEAP_ALLOCATED = 0,
|
||||
FBUFFER_STACK_ALLOCATED = 1,
|
||||
@ -46,6 +52,9 @@ typedef struct FBufferStruct {
|
||||
unsigned long initial_length;
|
||||
unsigned long len;
|
||||
unsigned long capa;
|
||||
#ifdef JSON_DEBUG
|
||||
unsigned long requested;
|
||||
#endif
|
||||
char *ptr;
|
||||
VALUE io;
|
||||
} FBuffer;
|
||||
@ -74,6 +83,20 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
|
||||
fb->ptr = stack_buffer;
|
||||
fb->capa = stack_buffer_size;
|
||||
}
|
||||
#ifdef JSON_DEBUG
|
||||
fb->requested = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
|
||||
{
|
||||
#ifdef JSON_DEBUG
|
||||
if (consumed > fb->requested) {
|
||||
rb_bug("fbuffer: Out of bound write");
|
||||
}
|
||||
fb->requested = 0;
|
||||
#endif
|
||||
fb->len += consumed;
|
||||
}
|
||||
|
||||
static void fbuffer_free(FBuffer *fb)
|
||||
@ -137,6 +160,10 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
|
||||
|
||||
static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
|
||||
{
|
||||
#ifdef JSON_DEBUG
|
||||
fb->requested = requested;
|
||||
#endif
|
||||
|
||||
if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
|
||||
fbuffer_do_inc_capa(fb, requested);
|
||||
}
|
||||
@ -147,15 +174,22 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
|
||||
if (len > 0) {
|
||||
fbuffer_inc_capa(fb, len);
|
||||
MEMCPY(fb->ptr + fb->len, newstr, char, len);
|
||||
fb->len += len;
|
||||
fbuffer_consumed(fb, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
|
||||
static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
|
||||
{
|
||||
#ifdef JSON_DEBUG
|
||||
if (fb->requested < 1) {
|
||||
rb_bug("fbuffer: unreserved write");
|
||||
}
|
||||
fb->requested--;
|
||||
#endif
|
||||
|
||||
fb->ptr[fb->len] = chr;
|
||||
fb->len += 1;
|
||||
fb->len++;
|
||||
}
|
||||
|
||||
static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
||||
@ -172,7 +206,7 @@ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
|
||||
{
|
||||
fbuffer_inc_capa(fb, 1);
|
||||
*(fb->ptr + fb->len) = newchr;
|
||||
fb->len++;
|
||||
fbuffer_consumed(fb, 1);
|
||||
}
|
||||
|
||||
static inline char *fbuffer_cursor(FBuffer *fb)
|
||||
@ -182,7 +216,7 @@ static inline char *fbuffer_cursor(FBuffer *fb)
|
||||
|
||||
static inline void fbuffer_advance_to(FBuffer *fb, char *end)
|
||||
{
|
||||
fb->len = end - fb->ptr;
|
||||
fbuffer_consumed(fb, (end - fb->ptr) - fb->len);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4,8 +4,9 @@ if RUBY_ENGINE == 'truffleruby'
|
||||
# The pure-Ruby generator is faster on TruffleRuby, so skip compiling the generator extension
|
||||
File.write('Makefile', dummy_makefile("").join)
|
||||
else
|
||||
append_cflags("-std=c99")
|
||||
append_cflags("-std=c99 -O0")
|
||||
$defs << "-DJSON_GENERATOR"
|
||||
$defs << "-DJSON_DEBUG" if ENV["JSON_DEBUG"]
|
||||
|
||||
if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
|
||||
if RbConfig::CONFIG['host_cpu'] =~ /^(arm.*|aarch64.*)/
|
||||
|
@ -404,7 +404,7 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
|
||||
if (!mask) {
|
||||
// Nothing to escape, ensure search_flush doesn't do anything by setting
|
||||
// search->cursor to search->ptr.
|
||||
search->buffer->len += remaining;
|
||||
fbuffer_consumed(search->buffer, remaining);
|
||||
search->ptr = search->end;
|
||||
search->cursor = search->end;
|
||||
return 0;
|
||||
@ -511,7 +511,7 @@ static inline TARGET_SSE2 FORCE_INLINE unsigned char search_escape_basic_sse2(se
|
||||
if (needs_escape_mask == 0) {
|
||||
// Nothing to escape, ensure search_flush doesn't do anything by setting
|
||||
// search->cursor to search->ptr.
|
||||
search->buffer->len += remaining;
|
||||
fbuffer_consumed(search->buffer, remaining);
|
||||
search->ptr = search->end;
|
||||
search->cursor = search->end;
|
||||
return 0;
|
||||
@ -1415,7 +1415,7 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
||||
/* fpconv_dtoa converts a float to its shortest string representation,
|
||||
* but it adds a ".0" if this is a plain integer.
|
||||
*/
|
||||
buffer->len += len;
|
||||
fbuffer_consumed(buffer, len);
|
||||
}
|
||||
|
||||
static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
||||
|
Loading…
x
Reference in New Issue
Block a user