Subject: Crash in Fjson_parse_buffer: ZV changes underneath it?

From: Daniel Colascione <[email-masked]>
Date: Thu, 27 Mar 2025 21:07:02 -0400

Somehow, the buffer changes underneath json_parse.  We pass an
out-of-bounds position to SET_PT_BOTH (position, byte), which either
asserts or crashes.  Not sure how the buffer could have changed ---
maybe a handler-bind?  The JSON parser doesn't seem to do anything
except allocate and signal.

The buffer itself is plenty big enough --- it's just that the accessible
region has somehow shrunk to nothing.

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
    frame #0: 0x000000010026d7a0 emacs`die(msg="charpos <= ZV && charpos >= BEGV", file="intervals.c", line=1873) at alloc.c:7450:12
    frame #1: 0x000000010037e3dc emacs`set_point_both(charpos=8, bytepos=8) at intervals.c:1873:3
    frame #2: 0x00000001003baf1c emacs`SET_PT_BOTH(position=8, byte=8) at buffer.h:182:3
  * frame #3: 0x00000001003bbadc emacs`Fjson_parse_buffer(nargs=6, args=(struct Lisp_Symbol *) $4 = 0x0000000270365e38) at json.c:1779:3
    frame #4: 0x00000001002bcd64 emacs`eval_sub(form=(struct Lisp_Cons
    *) $116 = 0x000000010831a440) at eval.c:2564:10

-> 1873	 eassert (charpos <= ZV && charpos >= BEGV);
   1874	
   1875	 have_overlays = buffer_has_overlays ();
   1876	
(lldb) print charpos
(ptrdiff_t) 8

(lldb) print *current_thread->m_current_buffer
(buffer) {
  header = (size = 4611686018645684300)
  name_ = 0x000000011ed08374 (struct Lisp_String *) $120 = 0x000000011ed08370
  last_name_ = 0x000000011ed08374 (struct Lisp_String *) $120 = 0x000000011ed08370
  filename_ = NULL
  directory_ = 0x0000000103708724 (struct Lisp_String *) $124 = 0x0000000103708720
  backed_up_ = NULL
  save_length_ = 0x0000000000000002 (EMACS_INT) $125 = 0
  auto_save_file_name_ = NULL
  read_only_ = NULL
  mark_ = 0x000000011e0113e5 (struct Lisp_Marker *) $128 = 0x000000011e0113e0
  local_var_alist_ = 0x000000012078c0b3 (struct Lisp_Cons *) $129 = 0x000000012078c0b0
  major_mode_ = 0x000000001f379d28 (struct Lisp_Symbol *) $131 = 0x000000011f8e8bc0
  local_minor_modes_ = 0x000000013042cff3 (struct Lisp_Cons *) $133 = 0x000000013042cff0
  mode_name_ = 0x000000013ee94fe4 (struct Lisp_String *) $134 = 0x000000013ee94fe0
  mode_line_format_ = 0x0000000110141db3 (struct Lisp_Cons *) $135 = 0x0000000110141db0
  header_line_format_ = NULL
  tab_line_format_ = NULL
  keymap_ = 0x00000001205abc33 (struct Lisp_Cons *) $136 = 0x00000001205abc30
  abbrev_table_ = 0x000000013f116a2d (struct Lisp_Obarray *) $139 = 0x000000013f116a28
  syntax_table_ = 0x000000013f116805 (struct Lisp_Vector *) $140 = 0x000000013f116800
  category_table_ = 0x000000010269d35d (struct Lisp_Vector *) $142 = 0x000000010269d358
  tab_width_ = 0x0000000000000022 (EMACS_INT) $143 = 8
  fill_column_ = 0x000000000000011a (EMACS_INT) $144 = 70
  left_margin_ = 0x0000000000000002 (EMACS_INT) $125 = 0
  auto_fill_function_ = NULL
  downcase_table_ = 0x000000010266a17d (struct Lisp_Vector *) $145 = 0x000000010266a178
  upcase_table_ = 0x00000001026590dd (struct Lisp_Vector *) $146 = 0x00000001026590d8
  case_canon_table_ = 0x000000010267b45d (struct Lisp_Vector *) $147 = 0x000000010267b458
  case_eqv_table_ = 0x000000010266a3bd (struct Lisp_Vector *) $148 = 0x000000010266a3b8
  truncate_lines_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  word_wrap_ = NULL
  ctl_arrow_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  bidi_display_reordering_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  bidi_paragraph_direction_ = NULL
  bidi_paragraph_separate_re_ = NULL
  bidi_paragraph_start_re_ = NULL
  selective_display_ = NULL
  selective_display_ellipses_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  overwrite_mode_ = NULL
  abbrev_mode_ = NULL
  display_table_ = NULL
  mark_active_ = NULL
  enable_multibyte_characters_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  buffer_file_coding_system_ = 0x00000000000127e0 (struct Lisp_Symbol *) $153 = 0x0000000100581678
  file_format_ = NULL
  auto_save_file_format_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  cache_long_scans_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  width_table_ = NULL
  pt_marker_ = NULL
  begv_marker_ = NULL
  zv_marker_ = NULL
  point_before_scroll_ = NULL
  file_truename_ = NULL
  invisibility_spec_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  last_selected_window_ = 0x0000000148490c15 (struct window *) $157 = 0x0000000148490c10
  display_count_ = 0x0000000000000006 (EMACS_INT) $159 = 1
  left_margin_cols_ = 0x0000000000000002 (EMACS_INT) $125 = 0
  right_margin_cols_ = 0x0000000000000002 (EMACS_INT) $125 = 0
  left_fringe_width_ = NULL
  right_fringe_width_ = NULL
  fringes_outside_margins_ = NULL
  scroll_bar_width_ = NULL
  scroll_bar_height_ = NULL
  vertical_scroll_bar_type_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  horizontal_scroll_bar_type_ = 0x0000000000000030 (struct Lisp_Symbol *) $150 = 0x000000010056eec8
  indicate_empty_lines_ = NULL
  indicate_buffer_boundaries_ = NULL
  fringe_indicator_alist_ = 0x0000000102656e8b (struct Lisp_Cons *) $160 = 0x0000000102656e88
  fringe_cursor_alist_ = 0x00000001026560db (struct Lisp_Cons *) $161 = 0x00000001026560d8
  display_time_ = 0x0000000110c15e73 (struct Lisp_Cons *) $162 = 0x0000000110c15e70
  scroll_up_aggressively_ = NULL
  scroll_down_aggressively_ = NULL
  cursor_type_ = NULL
  extra_line_spacing_ = NULL
  ts_parser_list_ = NULL
  text_conversion_style_ = NULL
  cursor_in_non_selected_windows_ = 0x0000000000009ba0 (struct Lisp_Symbol *) $164 = 0x0000000100578a38
  own_text = {
    beg = 0x0000000130088000 ""
    gpt = 1
    z = 74465
    gpt_byte = 1
    z_byte = 76476
    gap_size = 60247
    modiff = 15338
    chars_modiff = 15338
    save_modiff = 1
    overlay_modiff = 757
    compact = 1
    beg_unchanged = 0
    end_unchanged = 0
    unchanged_modified = 4374
    overlay_unchanged_modified = 755
    intervals = 0x000000011f38caa8
    markers = 0x000000011ffa4288
    inhibit_shrinking = false
    redisplay = true
  }
  text = 0x000000011e011268
  pt = 1
  pt_byte = 1
  begv = 1
  begv_byte = 1
  zv = 1
  zv_byte = 1
  base_buffer = NULL
  indirections = 0
  window_count = 1
  local_flags = "\0\0\0\0\0\0\0\0\U00000001\0\0\0\0\U00000001\0\U00000001\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\U00000001"
  modtime = (tv_sec = 0, tv_nsec = -2)
  modtime_size = -1
  auto_save_modified = 0
  display_error_modiff = 0
  auto_save_failure_time = 0
  last_window_start = 1
  newline_cache = 0x0000600000666300
  width_run_cache = NULL
  bidi_paragraph_cache = 0x000060000067afc0
  prevent_redisplay_optimizations_p = true
  clip_changed = true
  inhibit_buffer_hooks = false
  long_line_optimizations_p = false
  overlays = 0x00006000013c2a40
  undo_list_ = 0x0000000108985be3 (struct Lisp_Cons *) $166 =
  0x0000000108985be0

(lldb) print p.point_of_current_line 
(ptrdiff_t) 1
(lldb) print p.current_column 
(ptrdiff_t) 6

input_begin = 0x0000000130096b57 "\n     6 pass\n     620 skip\n [...]
input_current = 0x0000000130096b5e " pass\n     620 skip\n

The actual JSON we're parsing appears to be mangled somehow --- raw
newlines embedded in the output instead of being encapsulated inside
a string --- but that's a separate bug.