Skip to content

Commit 124c2cb

Browse files
authored
use default initializer for uninitialized globals (#363)
especially complex global variables (arrays, struct) need an initial value, or llvm will generate them as a external. So when accessing that global variable it would result in an ACCESS_VIOLATION fixes #361
1 parent 4dd88ca commit 124c2cb

6 files changed

+139
-32
lines changed

src/codegen/generators/variable_generator.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use crate::{
88
codegen::llvm_index::LlvmTypedIndex, compile_error::CompileError, index::VariableIndexEntry,
99
};
1010

11-
use super::{expression_generator::ExpressionCodeGenerator, llvm::Llvm};
11+
use super::{
12+
data_type_generator::get_default_for, expression_generator::ExpressionCodeGenerator, llvm::Llvm,
13+
};
1214

1315
pub fn generate_global_variables<'ctx, 'b>(
1416
module: &'b Module<'ctx>,
@@ -78,7 +80,11 @@ pub fn generate_global_variable<'ctx, 'b>(
7880
} else {
7981
None
8082
};
81-
let initial_value = initial_value.or_else(|| index.find_associated_initial_value(type_name));
83+
let initial_value = initial_value
84+
// 2nd try: find an associated default value for the declared type
85+
.or_else(|| index.find_associated_initial_value(type_name))
86+
// 3rd try: get the compiler's default for the given type (zero-initializer)
87+
.or_else(|| index.find_associated_type(type_name).map(get_default_for));
8288
let global_ir_variable = llvm.create_global_variable(
8389
module,
8490
global_variable.get_name(),

src/codegen/tests/code_gen_tests.rs

+27-30
Original file line numberDiff line numberDiff line change
@@ -4414,19 +4414,15 @@ fn structs_are_generated() {
44144414
44154415
VAR_GLOBAL
44164416
x : MyStruct;
4417+
y : STRUCT
4418+
a : BYTE;
4419+
b : BYTE;
4420+
END_STRUCT;
44174421
END_VAR
44184422
",
44194423
);
44204424

4421-
let expected = r#"; ModuleID = 'main'
4422-
source_filename = "main"
4423-
4424-
%MyStruct = type { i32, i32 }
4425-
4426-
@x = global %MyStruct zeroinitializer
4427-
"#;
4428-
4429-
assert_eq!(result, expected);
4425+
insta::assert_snapshot!(result);
44304426
}
44314427

44324428
#[test]
@@ -4437,17 +4433,12 @@ fn arrays_are_generated() {
44374433
44384434
VAR_GLOBAL
44394435
x : MyArray;
4436+
y : ARRAY[0..5] OF REAL;
44404437
END_VAR
44414438
",
44424439
);
44434440

4444-
let expected = r#"; ModuleID = 'main'
4445-
source_filename = "main"
4446-
4447-
@x = external global [10 x i16]
4448-
"#;
4449-
4450-
assert_eq!(result, expected);
4441+
insta::assert_snapshot!(result);
44514442
}
44524443

44534444
#[test]
@@ -4472,20 +4463,7 @@ fn arrays_with_global_const_size_are_generated() {
44724463
",
44734464
);
44744465

4475-
let expected = r#"; ModuleID = 'main'
4476-
source_filename = "main"
4477-
4478-
@THREE = global i16 3
4479-
@ZERO = global i16 0
4480-
@LEN = global i16 9
4481-
@x = external global [10 x i16]
4482-
@y = external global [11 x i32]
4483-
@z = external global [19 x i8]
4484-
@zz = external global [10 x [10 x i8]]
4485-
@zzz = external global [10 x [8 x i8]]
4486-
"#;
4487-
4488-
assert_eq!(result, expected);
4466+
insta::assert_snapshot!(result);
44894467
}
44904468

44914469
#[test]
@@ -5574,6 +5552,25 @@ source_filename = "main"
55745552
assert_eq!(result, expected);
55755553
}
55765554

5555+
#[test]
5556+
fn uninitialized_global_array() {
5557+
let result = codegen(
5558+
"
5559+
VAR_GLOBAL
5560+
a : ARRAY[0..1] OF BYTE;
5561+
END_VAR
5562+
",
5563+
);
5564+
5565+
let expected = r#"; ModuleID = 'main'
5566+
source_filename = "main"
5567+
5568+
@a = global [2 x i8] zeroinitializer
5569+
"#;
5570+
5571+
assert_eq!(result, expected);
5572+
}
5573+
55775574
#[test]
55785575
fn initial_values_in_array_variable_using_multiplied_statement() {
55795576
let result = codegen(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
source: src/codegen/tests/code_gen_tests.rs
3+
expression: result
4+
5+
---
6+
; ModuleID = 'main'
7+
source_filename = "main"
8+
9+
@x = global [10 x i16] zeroinitializer
10+
@y = global [6 x float] zeroinitializer
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
source: src/codegen/tests/code_gen_tests.rs
3+
expression: result
4+
5+
---
6+
; ModuleID = 'main'
7+
source_filename = "main"
8+
9+
@THREE = global i16 3
10+
@ZERO = global i16 0
11+
@LEN = global i16 9
12+
@x = global [10 x i16] zeroinitializer
13+
@y = global [11 x i32] zeroinitializer
14+
@z = global [19 x i8] zeroinitializer
15+
@zz = global [10 x [10 x i8]] zeroinitializer
16+
@zzz = global [10 x [8 x i8]] zeroinitializer
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
source: src/codegen/tests/code_gen_tests.rs
3+
expression: result
4+
5+
---
6+
; ModuleID = 'main'
7+
source_filename = "main"
8+
9+
%MyStruct = type { i32, i32 }
10+
%__global_y = type { i8, i8 }
11+
12+
@x = global %MyStruct zeroinitializer
13+
@y = global %__global_y zeroinitializer
14+

tests/correctness/global_variables.rs

+62
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,65 @@ fn global_variables_with_initialization() {
114114
}
115115
);
116116
}
117+
118+
#[test]
119+
fn uninitialized_global_array() {
120+
let function = r"
121+
VAR_GLOBAL
122+
gX : ARRAY[0..2] OF INT; /* this should be zero-initialized */
123+
gZ : INT;
124+
END_VAR
125+
FUNCTION main : REAL
126+
VAR
127+
x,y : INT;
128+
z : INT;
129+
END_VAR
130+
gX[0] := 10;
131+
gX[1] := 21;
132+
gZ := 5;
133+
x := gX[0];
134+
y := gX[1];
135+
z := gZ;
136+
main := (x + y) / z;
137+
END_FUNCTION
138+
";
139+
140+
struct MainType {}
141+
let mut maintype = MainType {};
142+
let res: f32 = compile_and_run(function.to_string(), &mut maintype);
143+
assert!((res - 31f32 / 5f32) <= f32::EPSILON);
144+
}
145+
146+
#[test]
147+
fn uninitialized_global_struct() {
148+
let function = r"
149+
TYPE Point : STRUCT
150+
x : INT;
151+
y : INT;
152+
END_STRUCT
153+
END_TYPE
154+
155+
VAR_GLOBAL
156+
gX : Point; /* this should be zero-initialized */
157+
gZ : INT;
158+
END_VAR
159+
FUNCTION main : REAL
160+
VAR
161+
x,y : INT;
162+
z : INT;
163+
END_VAR
164+
gX.x := 10;
165+
gX.y := 21;
166+
gZ := 5;
167+
x := gX.x;
168+
y := gX.y;
169+
z := gZ;
170+
main := (x + y) / z;
171+
END_FUNCTION
172+
";
173+
174+
struct MainType {}
175+
let mut maintype = MainType {};
176+
let res: f32 = compile_and_run(function.to_string(), &mut maintype);
177+
assert!((res - 31f32 / 5f32) <= f32::EPSILON);
178+
}

0 commit comments

Comments
 (0)