authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-02-01 16:47:26+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-02-22 21:01:44+00:00
logf0b331e95a45db5eb435c09c225471be0dac2b69
tree5bc692e50798a1c092138b42e06f93d93660ac21
parentdef7e2f20afa38417a195bb703179e0458ace274
signaturelock-open Commit is signed but in an unrecognized format.

langref: embrace the term "illegal behavior"

Also standardise the terms "safety-checked" and "unchecked".

4 files changed, 71 insertions(+), 55 deletions(-)

doc/langref.html.in+64-48
...@@ -1049,12 +1049,12 @@...@@ -1049,12 +1049,12 @@
1049 {#header_close#}1049 {#header_close#}
1050 {#header_open|Runtime Integer Values#}1050 {#header_open|Runtime Integer Values#}
1051 <p>1051 <p>
1052 Integer literals have no size limitation, and if any undefined behavior occurs,1052 Integer literals have no size limitation, and if any Illegal Behavior occurs,
1053 the compiler catches it.1053 the compiler catches it.
1054 </p>1054 </p>
1055 <p>1055 <p>
1056 However, once an integer value is no longer known at compile-time, it must have a1056 However, once an integer value is no longer known at compile-time, it must have a
1057 known size, and is vulnerable to undefined behavior.1057 known size, and is vulnerable to safety-checked {#link|Illegal Behavior#}.
1058 </p>1058 </p>
1059 {#code|runtime_vs_comptime.zig#}1059 {#code|runtime_vs_comptime.zig#}
10601060
...@@ -1064,7 +1064,7 @@...@@ -1064,7 +1064,7 @@
1064 {#link|Division by Zero#}.1064 {#link|Division by Zero#}.
1065 </p>1065 </p>
1066 <p>1066 <p>
1067 Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause undefined behavior on1067 Operators such as {#syntax#}+{#endsyntax#} and {#syntax#}-{#endsyntax#} cause {#link|Illegal Behavior#} on
1068 integer overflow. Alternative operators are provided for wrapping and saturating arithmetic on all targets.1068 integer overflow. Alternative operators are provided for wrapping and saturating arithmetic on all targets.
1069 {#syntax#}+%{#endsyntax#} and {#syntax#}-%{#endsyntax#} perform wrapping arithmetic1069 {#syntax#}+%{#endsyntax#} and {#syntax#}-%{#endsyntax#} perform wrapping arithmetic
1070 while {#syntax#}+|{#endsyntax#} and {#syntax#}-|{#endsyntax#} perform saturating arithmetic.1070 while {#syntax#}+|{#endsyntax#} and {#syntax#}-|{#endsyntax#} perform saturating arithmetic.
...@@ -2029,7 +2029,7 @@ or...@@ -2029,7 +2029,7 @@ or
2029 </p>2029 </p>
2030 <p>2030 <p>
2031 Slices have bounds checking and are therefore protected2031 Slices have bounds checking and are therefore protected
2032 against this kind of undefined behavior. This is one reason2032 against this kind of Illegal Behavior. This is one reason
2033 we prefer slices to pointers.2033 we prefer slices to pointers.
2034 </p>2034 </p>
2035 {#code|test_slice_bounds.zig#}2035 {#code|test_slice_bounds.zig#}
...@@ -2048,7 +2048,7 @@ or...@@ -2048,7 +2048,7 @@ or
20482048
2049 <p>2049 <p>
2050 {#link|@ptrCast#} converts a pointer's element type to another. This2050 {#link|@ptrCast#} converts a pointer's element type to another. This
2051 creates a new pointer that can cause undetectable illegal behavior2051 creates a new pointer that can cause undetectable Illegal Behavior
2052 depending on the loads and stores that pass through it. Generally, other2052 depending on the loads and stores that pass through it. Generally, other
2053 kinds of type conversions are preferable to2053 kinds of type conversions are preferable to
2054 {#syntax#}@ptrCast{#endsyntax#} if possible.2054 {#syntax#}@ptrCast{#endsyntax#} if possible.
...@@ -2164,7 +2164,7 @@ or...@@ -2164,7 +2164,7 @@ or
21642164
2165 <p>2165 <p>
2166 Sentinel-terminated slicing asserts that the element in the sentinel position of the backing data is2166 Sentinel-terminated slicing asserts that the element in the sentinel position of the backing data is
2167 actually the sentinel value. If this is not the case, safety-protected {#link|Undefined Behavior#} results.2167 actually the sentinel value. If this is not the case, safety-checked {#link|Illegal Behavior#} results.
2168 </p>2168 </p>
2169 {#code|test_sentinel_mismatch.zig#}2169 {#code|test_sentinel_mismatch.zig#}
21702170
...@@ -2425,7 +2425,7 @@ or...@@ -2425,7 +2425,7 @@ or
2425 or use an {#link|extern union#} or a {#link|packed union#} which have2425 or use an {#link|extern union#} or a {#link|packed union#} which have
2426 guaranteed in-memory layout.2426 guaranteed in-memory layout.
2427 {#link|Accessing the non-active field|Wrong Union Field Access#} is2427 {#link|Accessing the non-active field|Wrong Union Field Access#} is
2428 safety-checked {#link|Undefined Behavior#}:2428 safety-checked {#link|Illegal Behavior#}:
2429 </p>2429 </p>
2430 {#code|test_wrong_union_access.zig#}2430 {#code|test_wrong_union_access.zig#}
24312431
...@@ -3023,11 +3023,11 @@ or...@@ -3023,11 +3023,11 @@ or
3023 {#syntax#}const number = parseU64("1234", 10) catch unreachable;{#endsyntax#}3023 {#syntax#}const number = parseU64("1234", 10) catch unreachable;{#endsyntax#}
3024 <p>3024 <p>
3025 Here we know for sure that "1234" will parse successfully. So we put the3025 Here we know for sure that "1234" will parse successfully. So we put the
3026 {#syntax#}unreachable{#endsyntax#} value on the right hand side. {#syntax#}unreachable{#endsyntax#} generates3026 {#syntax#}unreachable{#endsyntax#} value on the right hand side.
3027 a panic in {#link|Debug#} and {#link|ReleaseSafe#} modes and undefined behavior in3027 {#syntax#}unreachable{#endsyntax#} invokes safety-checked {#link|Illegal Behavior#}, so
3028 {#link|ReleaseFast#} and {#link|ReleaseSmall#} modes. So, while we're debugging the3028 in {#link|Debug#} and {#link|ReleaseSafe#}, triggers a safety panic by default. So, while
3029 application, if there <em>was</em> a surprise error here, the application would crash3029 we're debugging the application, if there <em>was</em> a surprise error here, the application
3030 appropriately.3030 would crash appropriately.
3031 </p>3031 </p>
3032 <p>3032 <p>
3033 You may want to take a different action for every situation. For that, we combine3033 You may want to take a different action for every situation. For that, we combine
...@@ -4034,7 +4034,7 @@ fn performFn(start_value: i32) i32 {...@@ -4034,7 +4034,7 @@ fn performFn(start_value: i32) i32 {
4034 </p>4034 </p>
4035 <p>4035 <p>
4036 Luckily, we used an unsigned integer, and so when we tried to subtract 1 from 0, it triggered4036 Luckily, we used an unsigned integer, and so when we tried to subtract 1 from 0, it triggered
4037 undefined behavior, which is always a compile error if the compiler knows it happened.4037 {#link|Illegal Behavior#}, which is always a compile error if the compiler knows it happened.
4038 But what would have happened if we used a signed integer?4038 But what would have happened if we used a signed integer?
4039 </p>4039 </p>
4040 {#code|fibonacci_comptime_infinite_recursion.zig#}4040 {#code|fibonacci_comptime_infinite_recursion.zig#}
...@@ -4239,7 +4239,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {...@@ -4239,7 +4239,7 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {
4239 </p>4239 </p>
4240 <p>4240 <p>
4241 Failure to declare the full set of clobbers for a given inline assembly4241 Failure to declare the full set of clobbers for a given inline assembly
4242 expression is unchecked {#link|Undefined Behavior#}.4242 expression is unchecked {#link|Illegal Behavior#}.
4243 </p>4243 </p>
4244 {#header_close#}4244 {#header_close#}
42454245
...@@ -4805,7 +4805,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4805,7 +4805,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4805 </p>4805 </p>
4806 <p>4806 <p>
4807 Attempting to convert an integer with no corresponding value in the enum invokes4807 Attempting to convert an integer with no corresponding value in the enum invokes
4808 safety-checked {#link|Undefined Behavior#}.4808 safety-checked {#link|Illegal Behavior#}.
4809 Note that a {#link|non-exhaustive enum|Non-exhaustive enum#} has corresponding values for all4809 Note that a {#link|non-exhaustive enum|Non-exhaustive enum#} has corresponding values for all
4810 integers in the enum's integer tag type: the {#syntax#}_{#endsyntax#} value represents all4810 integers in the enum's integer tag type: the {#syntax#}_{#endsyntax#} value represents all
4811 the remaining unnamed integers in the enum's tag type.4811 the remaining unnamed integers in the enum's tag type.
...@@ -4824,7 +4824,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4824,7 +4824,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4824 </p>4824 </p>
4825 <p>4825 <p>
4826 Attempting to convert an integer that does not correspond to any error results in4826 Attempting to convert an integer that does not correspond to any error results in
4827 safety-protected {#link|Undefined Behavior#}.4827 safety-checked {#link|Illegal Behavior#}.
4828 </p>4828 </p>
4829 {#see_also|@intFromError#}4829 {#see_also|@intFromError#}
4830 {#header_close#}4830 {#header_close#}
...@@ -4856,7 +4856,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4856,7 +4856,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4856 <p>4856 <p>
4857 Converts an error set or error union value from one error set to another error set. The return type is the4857 Converts an error set or error union value from one error set to another error set. The return type is the
4858 inferred result type. Attempting to convert an error which is not in the destination error4858 inferred result type. Attempting to convert an error which is not in the destination error
4859 set results in safety-protected {#link|Undefined Behavior#}.4859 set results in safety-checked {#link|Illegal Behavior#}.
4860 </p>4860 </p>
4861 {#header_close#}4861 {#header_close#}
48624862
...@@ -4912,7 +4912,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4912,7 +4912,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4912 </p>4912 </p>
4913 <p>4913 <p>
4914 If {#syntax#}field_ptr{#endsyntax#} does not point to the {#syntax#}field_name{#endsyntax#} field of an instance of4914 If {#syntax#}field_ptr{#endsyntax#} does not point to the {#syntax#}field_name{#endsyntax#} field of an instance of
4915 the result type, and the result type has ill-defined layout, invokes unchecked {#link|Undefined Behavior#}.4915 the result type, and the result type has ill-defined layout, invokes unchecked {#link|Illegal Behavior#}.
4916 </p>4916 </p>
4917 {#header_close#}4917 {#header_close#}
49184918
...@@ -5029,7 +5029,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5029,7 +5029,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5029 Converts an integer to another integer while keeping the same numerical value.5029 Converts an integer to another integer while keeping the same numerical value.
5030 The return type is the inferred result type.5030 The return type is the inferred result type.
5031 Attempting to convert a number which is out of range of the destination type results in5031 Attempting to convert a number which is out of range of the destination type results in
5032 safety-protected {#link|Undefined Behavior#}.5032 safety-checked {#link|Illegal Behavior#}.
5033 </p>5033 </p>
5034 {#code|test_intCast_builtin.zig#}5034 {#code|test_intCast_builtin.zig#}
50355035
...@@ -5090,7 +5090,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5090,7 +5090,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5090 </p>5090 </p>
5091 <p>5091 <p>
5092 If the integer part of the floating point number cannot fit in the destination type,5092 If the integer part of the floating point number cannot fit in the destination type,
5093 it invokes safety-checked {#link|Undefined Behavior#}.5093 it invokes safety-checked {#link|Illegal Behavior#}.
5094 </p>5094 </p>
5095 {#see_also|@floatFromInt#}5095 {#see_also|@floatFromInt#}
5096 {#header_close#}5096 {#header_close#}
...@@ -5250,7 +5250,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5250,7 +5250,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5250 <p>5250 <p>
5251 The {#syntax#}ptr{#endsyntax#} argument may be any pointer type and determines the memory5251 The {#syntax#}ptr{#endsyntax#} argument may be any pointer type and determines the memory
5252 address to prefetch. This function does not dereference the pointer, it is perfectly legal5252 address to prefetch. This function does not dereference the pointer, it is perfectly legal
5253 to pass a pointer to invalid memory to this function and no illegal behavior will result.5253 to pass a pointer to invalid memory to this function and no Illegal Behavior will result.
5254 </p>5254 </p>
5255 <p>{#syntax#}PrefetchOptions{#endsyntax#} can be found with {#syntax#}@import("std").builtin.PrefetchOptions{#endsyntax#}.</p>5255 <p>{#syntax#}PrefetchOptions{#endsyntax#} can be found with {#syntax#}@import("std").builtin.PrefetchOptions{#endsyntax#}.</p>
5256 {#header_close#}5256 {#header_close#}
...@@ -5262,7 +5262,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5262,7 +5262,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5262 </p>5262 </p>
5263 <p>5263 <p>
5264 {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#}5264 {#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#}
5265 to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}.5265 to a non-optional pointer invokes safety-checked {#link|Illegal Behavior#}.
5266 </p>5266 </p>
5267 <p>5267 <p>
5268 {#syntax#}@ptrCast{#endsyntax#} cannot be used for:5268 {#syntax#}@ptrCast{#endsyntax#} cannot be used for:
...@@ -5286,7 +5286,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5286,7 +5286,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5286 </p>5286 </p>
5287 <p>5287 <p>
5288 If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#}5288 If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#}
5289 is zero, this invokes safety-checked {#link|Undefined Behavior#}.5289 is zero, this invokes safety-checked {#link|Illegal Behavior#}.
5290 </p>5290 </p>
5291 {#header_close#}5291 {#header_close#}
52925292
...@@ -5361,8 +5361,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5361,8 +5361,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5361 <li>5361 <li>
5362 {#syntax#}Optimized{#endsyntax#} - Floating point operations may do all of the following:5362 {#syntax#}Optimized{#endsyntax#} - Floating point operations may do all of the following:
5363 <ul>5363 <ul>
5364 <li>Assume the arguments and result are not NaN. Optimizations are required to retain defined behavior over NaNs, but the value of the result is undefined.</li>5364 <li>Assume the arguments and result are not NaN. Optimizations are required to retain legal behavior over NaNs, but the value of the result is undefined.</li>
5365 <li>Assume the arguments and result are not +/-Inf. Optimizations are required to retain defined behavior over +/-Inf, but the value of the result is undefined.</li>5365 <li>Assume the arguments and result are not +/-Inf. Optimizations are required to retain legal behavior over +/-Inf, but the value of the result is undefined.</li>
5366 <li>Treat the sign of a zero argument or result as insignificant.</li>5366 <li>Treat the sign of a zero argument or result as insignificant.</li>
5367 <li>Use the reciprocal of an argument rather than perform division.</li>5367 <li>Use the reciprocal of an argument rather than perform division.</li>
5368 <li>Perform floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-add).</li>5368 <li>Perform floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-add).</li>
...@@ -5401,7 +5401,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5401,7 +5401,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5401 </p>5401 </p>
5402 <p>5402 <p>
5403 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits.5403 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits.
5404 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} is undefined behavior.5404 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
5405 </p>5405 </p>
5406 <p>5406 <p>
5407 {#syntax#}comptime_int{#endsyntax#} is modeled as an integer with an infinite number of bits,5407 {#syntax#}comptime_int{#endsyntax#} is modeled as an integer with an infinite number of bits,
...@@ -5418,7 +5418,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5418,7 +5418,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5418 </p>5418 </p>
5419 <p>5419 <p>
5420 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(@TypeOf(a)).int.bits){#endsyntax#} bits.5420 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(@TypeOf(a)).int.bits){#endsyntax#} bits.
5421 This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).int.bits{#endsyntax#} is undefined behavior.5421 This is because {#syntax#}shift_amt >= @typeInfo(@TypeOf(a)).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
5422 </p>5422 </p>
5423 {#see_also|@shlExact|@shrExact#}5423 {#see_also|@shlExact|@shrExact#}
5424 {#header_close#}5424 {#header_close#}
...@@ -5431,7 +5431,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5431,7 +5431,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5431 </p>5431 </p>
5432 <p>5432 <p>
5433 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits.5433 The type of {#syntax#}shift_amt{#endsyntax#} is an unsigned integer with {#syntax#}log2(@typeInfo(T).int.bits){#endsyntax#} bits.
5434 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} is undefined behavior.5434 This is because {#syntax#}shift_amt >= @typeInfo(T).int.bits{#endsyntax#} triggers safety-checked {#link|Illegal Behavior#}.
5435 </p>5435 </p>
5436 {#see_also|@shlExact|@shlWithOverflow#}5436 {#see_also|@shlExact|@shlWithOverflow#}
5437 {#header_close#}5437 {#header_close#}
...@@ -5706,7 +5706,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5706,7 +5706,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5706 {#header_open|@tagName#}5706 {#header_open|@tagName#}
5707 <pre>{#syntax#}@tagName(value: anytype) [:0]const u8{#endsyntax#}</pre>5707 <pre>{#syntax#}@tagName(value: anytype) [:0]const u8{#endsyntax#}</pre>
5708 <p>5708 <p>
5709 Converts an enum value or union value to a string literal representing the name.</p><p>If the enum is non-exhaustive and the tag value does not map to a name, it invokes safety-checked {#link|Undefined Behavior#}.5709 Converts an enum value or union value to a string literal representing the name.</p><p>If the enum is non-exhaustive and the tag value does not map to a name, it invokes safety-checked {#link|Illegal Behavior#}.
5710 </p>5710 </p>
5711 {#header_close#}5711 {#header_close#}
57125712
...@@ -5943,7 +5943,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5943,7 +5943,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5943 <li>Reproducible build</li>5943 <li>Reproducible build</li>
5944 </ul>5944 </ul>
5945 {#header_close#}5945 {#header_close#}
5946 {#see_also|Compile Variables|Zig Build System|Undefined Behavior#}5946 {#see_also|Compile Variables|Zig Build System|Illegal Behavior#}
5947 {#header_close#}5947 {#header_close#}
59485948
5949 {#header_open|Single Threaded Builds#}5949 {#header_open|Single Threaded Builds#}
...@@ -5958,20 +5958,36 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -5958,20 +5958,36 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
5958 </ul>5958 </ul>
5959 {#header_close#}5959 {#header_close#}
59605960
5961 {#header_open|Undefined Behavior#}5961 {#header_open|Illegal Behavior#}
5962 <p>5962 <p>
5963 Zig has many instances of undefined behavior. If undefined behavior is5963 Many operations in Zig trigger what is known as "Illegal Behavior" (IB). If Illegal Behavior is detected at
5964 detected at compile-time, Zig emits a compile error and refuses to continue.5964 compile-time, Zig emits a compile error and refuses to continue. Otherwise, when Illegal Behavior is not caught
5965 Most undefined behavior that cannot be detected at compile-time can be detected5965 at compile-time, it falls into one of two categories.
5966 at runtime. In these cases, Zig has safety checks. Safety checks can be disabled
5967 on a per-block basis with {#link|@setRuntimeSafety#}. The {#link|ReleaseFast#}
5968 and {#link|ReleaseSmall#} build modes disable all safety checks (except where overridden
5969 by {#link|@setRuntimeSafety#}) in order to facilitate optimizations.
5970 </p>5966 </p>
5971 <p>5967 <p>
5972 When a safety check fails, Zig crashes with a stack trace, like this:5968 Some Illegal Behavior is <em>safety-checked</em>: this means that the compiler will insert "safety checks"
5969 anywhere that the Illegal Behavior may occur at runtime, to determine whether it is about to happen. If it
5970 is, the safety check "fails", which triggers a panic.
5973 </p>5971 </p>
5974 {#code|test_undefined_behavior.zig#}5972 <p>
5973 All other Illegal Behavior is <em>unchecked</em>, meaning the compiler is unable to insert safety checks for
5974 it. If Unchecked Illegal Behavior is invoked at runtime, anything can happen: usually that will be some kind of
5975 crash, but the optimizer is free to make Unchecked Illegal Behavior do anything, such as calling arbitrary functions
5976 or clobbering arbitrary data. This is similar to the concept of "undefined behavior" in some other languages. Note that
5977 Unchecked Illegal Behavior still always results in a compile error if evaluated at {#link|comptime#}, because the Zig
5978 compiler is able to perform more sophisticated checks at compile-time than at runtime.
5979 </p>
5980 <p>
5981 Most Illegal Behavior is safety-checked. However, to facilitate optimizations, safety checks are disabled by default
5982 in the {#link|ReleaseFast#} and {#link|ReleaseSmall#} optimization modes. Safety checks can also be enabled or disabled
5983 on a per-block basis, overriding the default for the current optimization mode, using {#link|@setRuntimeSafety#}. When
5984 safety checks are disabled, Safety-Checked Illegal Behavior behaves like Unchecked Illegal Behavior; that is, any behavior
5985 may result from invoking it.
5986 </p>
5987 <p>
5988 When a safety check fails, Zig's default panic handler crashes with a stack trace, like this:
5989 </p>
5990 {#code|test_illegal_behavior.zig#}
59755991
5976 {#header_open|Reaching Unreachable Code#}5992 {#header_open|Reaching Unreachable Code#}
5977 <p>At compile-time:</p>5993 <p>At compile-time:</p>
...@@ -6337,7 +6353,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -6337,7 +6353,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
6337 <p>6353 <p>
6338 {#syntax#}var{#endsyntax#} declarations inside functions are stored in the function's stack frame. Once a function returns,6354 {#syntax#}var{#endsyntax#} declarations inside functions are stored in the function's stack frame. Once a function returns,
6339 any {#link|Pointers#} to variables in the function's stack frame become invalid references, and6355 any {#link|Pointers#} to variables in the function's stack frame become invalid references, and
6340 dereferencing them becomes unchecked {#link|Undefined Behavior#}.6356 dereferencing them becomes unchecked {#link|Illegal Behavior#}.
6341 </p>6357 </p>
6342 <p>6358 <p>
6343 {#syntax#}var{#endsyntax#} declarations at the top level or in {#link|struct#} declarations are stored in the global6359 {#syntax#}var{#endsyntax#} declarations at the top level or in {#link|struct#} declarations are stored in the global
...@@ -6445,7 +6461,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -6445,7 +6461,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
6445 The API documentation for functions and data structures should take great care to explain6461 The API documentation for functions and data structures should take great care to explain
6446 the ownership and lifetime semantics of pointers. Ownership determines whose responsibility it6462 the ownership and lifetime semantics of pointers. Ownership determines whose responsibility it
6447 is to free the memory referenced by the pointer, and lifetime determines the point at which6463 is to free the memory referenced by the pointer, and lifetime determines the point at which
6448 the memory becomes inaccessible (lest {#link|Undefined Behavior#} occur).6464 the memory becomes inaccessible (lest {#link|Illegal Behavior#} occur).
6449 </p>6465 </p>
6450 {#header_close#}6466 {#header_close#}
64516467
...@@ -6733,10 +6749,10 @@ int foo(void) {...@@ -6733,10 +6749,10 @@ int foo(void) {
6733 <li>Supports all the syntax of the other two pointer types ({#syntax#}*T{#endsyntax#}) and ({#syntax#}[*]T{#endsyntax#}).</li>6749 <li>Supports all the syntax of the other two pointer types ({#syntax#}*T{#endsyntax#}) and ({#syntax#}[*]T{#endsyntax#}).</li>
6734 <li>Coerces to other pointer types, as well as {#link|Optional Pointers#}.6750 <li>Coerces to other pointer types, as well as {#link|Optional Pointers#}.
6735 When a C pointer is coerced to a non-optional pointer, safety-checked6751 When a C pointer is coerced to a non-optional pointer, safety-checked
6736 {#link|Undefined Behavior#} occurs if the address is 0.6752 {#link|Illegal Behavior#} occurs if the address is 0.
6737 </li>6753 </li>
6738 <li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked6754 <li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked
6739 {#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of6755 {#link|Illegal Behavior#}. Optional C pointers introduce another bit to keep track of
6740 null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer6756 null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer
6741 is unnecessary as one can use normal {#link|Optional Pointers#}.6757 is unnecessary as one can use normal {#link|Optional Pointers#}.
6742 </li>6758 </li>
...@@ -7051,8 +7067,8 @@ fn readU32Be() u32 {}...@@ -7051,8 +7067,8 @@ fn readU32Be() u32 {}
7051 <ul>7067 <ul>
7052 <li>Omit any information that is redundant based on the name of the thing being documented.</li>7068 <li>Omit any information that is redundant based on the name of the thing being documented.</li>
7053 <li>Duplicating information onto multiple similar functions is encouraged because it helps IDEs and other tools provide better help text.</li>7069 <li>Duplicating information onto multiple similar functions is encouraged because it helps IDEs and other tools provide better help text.</li>
7054 <li>Use the word <strong>assume</strong> to indicate invariants that cause {#link|Undefined Behavior#} when violated.</li>7070 <li>Use the word <strong>assume</strong> to indicate invariants that cause <em>unchecked</em> {#link|Illegal Behavior#} when violated.</li>
7055 <li>Use the word <strong>assert</strong> to indicate invariants that cause <em>safety-checked</em> {#link|Undefined Behavior#} when violated.</li>7071 <li>Use the word <strong>assert</strong> to indicate invariants that cause <em>safety-checked</em> {#link|Illegal Behavior#} when violated.</li>
7056 </ul>7072 </ul>
7057 {#header_close#}7073 {#header_close#}
7058 {#header_close#}7074 {#header_close#}
...@@ -7448,8 +7464,8 @@ fn readU32Be() u32 {}...@@ -7448,8 +7464,8 @@ fn readU32Be() u32 {}
7448 In particular, inside a {#syntax#}nosuspend{#endsyntax#} scope:7464 In particular, inside a {#syntax#}nosuspend{#endsyntax#} scope:
7449 <ul>7465 <ul>
7450 <li>Using the {#syntax#}suspend{#endsyntax#} keyword results in a compile error.</li>7466 <li>Using the {#syntax#}suspend{#endsyntax#} keyword results in a compile error.</li>
7451 <li>Using {#syntax#}await{#endsyntax#} on a function frame which hasn't completed yet results in safety-checked {#link|Undefined Behavior#}.</li>7467 <li>Using {#syntax#}await{#endsyntax#} on a function frame which hasn't completed yet results in safety-checked {#link|Illegal Behavior#}.</li>
7452 <li>Calling an async function may result in safety-checked {#link|Undefined Behavior#}, because it's equivalent to <code>await async some_async_fn()</code>, which contains an {#syntax#}await{#endsyntax#}.</li>7468 <li>Calling an async function may result in safety-checked {#link|Illegal Behavior#}, because it's equivalent to <code>await async some_async_fn()</code>, which contains an {#syntax#}await{#endsyntax#}.</li>
7453 </ul>7469 </ul>
7454 Code inside a {#syntax#}nosuspend{#endsyntax#} scope does not cause the enclosing function to become an {#link|async function|Async Functions#}.7470 Code inside a {#syntax#}nosuspend{#endsyntax#} scope does not cause the enclosing function to become an {#link|async function|Async Functions#}.
7455 <ul>7471 <ul>
doc/langref/test_illegal_behavior.zig created+5
...@@ -0,0 +1,5 @@
1test "safety check" {
2 unreachable;
3}
4
5// test_error=reached unreachable code
doc/langref/test_setRuntimeSafety_builtin.zig+2-2
...@@ -2,7 +2,7 @@ test "@setRuntimeSafety" {...@@ -2,7 +2,7 @@ test "@setRuntimeSafety" {
2 // The builtin applies to the scope that it is called in. So here, integer overflow2 // The builtin applies to the scope that it is called in. So here, integer overflow
3 // will not be caught in ReleaseFast and ReleaseSmall modes:3 // will not be caught in ReleaseFast and ReleaseSmall modes:
4 // var x: u8 = 255;4 // var x: u8 = 255;
5 // x += 1; // undefined behavior in ReleaseFast/ReleaseSmall modes.5 // x += 1; // Unchecked Illegal Behavior in ReleaseFast/ReleaseSmall modes.
6 {6 {
7 // However this block has safety enabled, so safety checks happen here,7 // However this block has safety enabled, so safety checks happen here,
8 // even in ReleaseFast and ReleaseSmall modes.8 // even in ReleaseFast and ReleaseSmall modes.
...@@ -15,7 +15,7 @@ test "@setRuntimeSafety" {...@@ -15,7 +15,7 @@ test "@setRuntimeSafety" {
15 // would not be caught in any build mode.15 // would not be caught in any build mode.
16 @setRuntimeSafety(false);16 @setRuntimeSafety(false);
17 // var x: u8 = 255;17 // var x: u8 = 255;
18 // x += 1; // undefined behavior in all build modes.18 // x += 1; // Unchecked Illegal Behavior in all build modes.
19 }19 }
20 }20 }
21}21}
doc/langref/test_undefined_behavior.zig deleted-5
...@@ -1,5 +0,0 @@
1test "safety check" {
2 unreachable;
3}
4
5// test_error=reached unreachable code