Skip to content

Commit 20fc614

Browse files
flambda-backend: Check that stack frames are not too large (#10085) (oxcaml#561)
The frame table uses 16-bit unsigned integers to store the size of a stack frame as well as the number and offsets of roots. This commit adds a compile-time error if these 16-bit fields overflow. Closes: #10072 Co-authored-by: Xavier Leroy <xavierleroy@users.noreply.github.com>
1 parent 5fc2e95 commit 20fc614

5 files changed

Lines changed: 40 additions & 7 deletions

File tree

.depend

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,6 +2149,7 @@ asmcomp/asmgen.cmo : \
21492149
asmcomp/linscan.cmi \
21502150
asmcomp/linearize.cmi \
21512151
file_formats/linear_format.cmi \
2152+
asmcomp/linear.cmi \
21522153
lambda/lambda.cmi \
21532154
asmcomp/interval.cmi \
21542155
asmcomp/interf.cmi \
@@ -2191,6 +2192,7 @@ asmcomp/asmgen.cmx : \
21912192
asmcomp/linscan.cmx \
21922193
asmcomp/linearize.cmx \
21932194
file_formats/linear_format.cmx \
2195+
asmcomp/linear.cmx \
21942196
lambda/lambda.cmx \
21952197
asmcomp/interval.cmx \
21962198
asmcomp/interf.cmx \
@@ -2214,6 +2216,7 @@ asmcomp/asmgen.cmx : \
22142216
asmcomp/asmgen.cmi
22152217
asmcomp/asmgen.cmi : \
22162218
lambda/lambda.cmi \
2219+
asmcomp/emitaux.cmi \
22172220
asmcomp/cmm.cmi \
22182221
middle_end/clambda.cmi \
22192222
middle_end/backend_intf.cmi

asmcomp/asmgen.ml

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ open Cmm
2626
type error =
2727
| Assembler_error of string
2828
| Mismatched_for_pack of string option
29+
| Asm_generation of string * Emitaux.error
2930

3031
exception Error of error
3132

@@ -96,9 +97,13 @@ let if_emit_do f x = if should_emit () then f x else ()
9697
let emit_begin_assembly = if_emit_do Emit.begin_assembly
9798
let emit_end_assembly = if_emit_do Emit.end_assembly
9899
let emit_data = if_emit_do Emit.data
99-
let emit_fundecl =
100-
if_emit_do
101-
(Profile.record ~accumulate:true "emit" Emit.fundecl)
100+
let emit_fundecl fd =
101+
if should_emit() then begin
102+
try
103+
Profile.record ~accumulate:true "emit" Emit.fundecl fd
104+
with Emitaux.Error e ->
105+
raise (Error (Asm_generation(fd.Linear.fun_name, e)))
106+
end
102107

103108
let rec regalloc ~ppf_dump round fd =
104109
if round > 50 then
@@ -290,6 +295,10 @@ let report_error ppf = function
290295
fprintf ppf
291296
"This input file cannot be compiled %s: it was generated %s."
292297
(msg !Clflags.for_package) (msg saved)
298+
| Asm_generation(fn, err) ->
299+
fprintf ppf
300+
"Error producing assembly code for function %s: %a"
301+
fn Emitaux.report_error err
293302

294303
let () =
295304
Location.register_error_of_exn

asmcomp/asmgen.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ val compile_phrase :
4444
type error =
4545
| Assembler_error of string
4646
| Mismatched_for_pack of string option
47+
| Asm_generation of string * Emitaux.error
4748

4849
exception Error of error
4950
val report_error: Format.formatter -> error -> unit

asmcomp/emitaux.ml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515

1616
(* Common functions for emitting assembly code *)
1717

18+
type error =
19+
| Stack_frame_too_large of int
20+
21+
exception Error of error
22+
1823
let output_channel = ref stdout
1924

2025
let emit_string s = output_string !output_channel s
@@ -178,6 +183,12 @@ let emit_frames a =
178183
Label_table.add debuginfos key lbl;
179184
lbl
180185
in
186+
let efa_16_checked n =
187+
assert (n >= 0);
188+
if n < 0x1_0000
189+
then a.efa_16 n
190+
else raise (Error(Stack_frame_too_large n))
191+
in
181192
let emit_frame fd =
182193
assert (fd.fd_frame_size land 3 = 0);
183194
let flags =
@@ -191,9 +202,9 @@ let emit_frames a =
191202
then 3 else 2
192203
in
193204
a.efa_code_label fd.fd_lbl;
194-
a.efa_16 (fd.fd_frame_size + flags);
195-
a.efa_16 (List.length fd.fd_live_offset);
196-
List.iter a.efa_16 fd.fd_live_offset;
205+
efa_16_checked (fd.fd_frame_size + flags);
206+
efa_16_checked (List.length fd.fd_live_offset);
207+
List.iter efa_16_checked fd.fd_live_offset;
197208
begin match fd.fd_debuginfo with
198209
| _ when flags = 0 ->
199210
()
@@ -370,3 +381,7 @@ let reset () =
370381

371382
let binary_backend_available = ref false
372383
let create_asm_file = ref true
384+
385+
let report_error ppf = function
386+
| Stack_frame_too_large n ->
387+
Format.fprintf ppf "stack frame too large (%d bytes)" n

asmcomp/emitaux.mli

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,16 @@ val cfi_endproc : unit -> unit
7171
val cfi_adjust_cfa_offset : int -> unit
7272
val cfi_offset : reg:int -> offset:int -> unit
7373

74-
7574
val binary_backend_available: bool ref
7675
(** Is a binary backend available. If yes, we don't need
7776
to generate the textual assembly file (unless the user
7877
request it with -S). *)
7978

8079
val create_asm_file: bool ref
8180
(** Are we actually generating the textual assembly file? *)
81+
82+
type error =
83+
| Stack_frame_too_large of int
84+
85+
exception Error of error
86+
val report_error: Format.formatter -> error -> unit

0 commit comments

Comments
 (0)