mirror of
https://github.com/dlang/dmd.git
synced 2025-04-25 12:40:11 +03:00
purge changelog
This commit is contained in:
parent
c403accecf
commit
c6863be720
31 changed files with 0 additions and 673 deletions
|
@ -1,19 +0,0 @@
|
|||
Storage classes `ref` and `auto ref` can now be applied to local, static, extern, and global variables
|
||||
|
||||
For example, one can now write:
|
||||
```
|
||||
struct S { int a; }
|
||||
|
||||
void main()
|
||||
{
|
||||
S s;
|
||||
ref int r = s.a;
|
||||
r = 3;
|
||||
assert(s.a == 3);
|
||||
|
||||
auto ref x = 0;
|
||||
auto ref y = x;
|
||||
static assert(!__traits(isRef, x));
|
||||
static assert( __traits(isRef, y));
|
||||
}
|
||||
```
|
|
@ -1,18 +0,0 @@
|
|||
Keywords `auto` and `ref` must be adjacent
|
||||
|
||||
It's now deprecated to declare `auto ref` parameters without putting those two keywords next to each other.
|
||||
This way it's clear that `auto ref` semantics are intended, rather than `ref` and `auto` semantics separately.
|
||||
For the newly introduced $(RELATIVE_LINK2 dmd.reflocal, `ref` local / global variables), it's an error immediately.
|
||||
|
||||
---
|
||||
void t()(ref const auto int x) // Deprecation
|
||||
{
|
||||
ref auto y = x; // Error
|
||||
}
|
||||
|
||||
// Correction:
|
||||
void t()(auto ref const int x)
|
||||
{
|
||||
auto ref y = x;
|
||||
}
|
||||
---
|
|
@ -1,23 +0,0 @@
|
|||
The `align` attribute now allows specifying `default` explicitly
|
||||
|
||||
A lone `align` sets the alignment to the type’s default.
|
||||
To be more explicit, `align(default)` does the same.
|
||||
|
||||
```
|
||||
struct S
|
||||
{
|
||||
align(4)
|
||||
{
|
||||
byte x;
|
||||
align(default) long y;
|
||||
long z;
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
pragma(msg, S.x.alignof); // 4
|
||||
pragma(msg, S.y.alignof); // 8
|
||||
pragma(msg, S.z.alignof); // 4
|
||||
}
|
||||
```
|
|
@ -1,15 +0,0 @@
|
|||
Remove `delete` as a keyword
|
||||
|
||||
After being superseded by `destroy()`, deprecated, and turned into an error, `delete` can now be used as an identifier:
|
||||
|
||||
---
|
||||
enum Action
|
||||
{
|
||||
add, delete
|
||||
}
|
||||
|
||||
void delete(T)(T obj)
|
||||
{
|
||||
|
||||
}
|
||||
---
|
|
@ -1,18 +0,0 @@
|
|||
Case fallthough for multivalued cases is an error now
|
||||
|
||||
This used to give a deprecation and now gives an error:
|
||||
```
|
||||
int i;
|
||||
switch (0)
|
||||
{
|
||||
case 0, 1: i = 20;
|
||||
default: assert(0); // Error: switch case fallthrough - use 'goto default;' if intended
|
||||
}
|
||||
|
||||
switch (0)
|
||||
{
|
||||
default:
|
||||
case 0, 1: i = 20;
|
||||
case 2, 3: i = 30; // Error: switch case fallthrough - use 'goto case;' if intended
|
||||
}
|
||||
```
|
|
@ -1,32 +0,0 @@
|
|||
An error is now given for constructors when a field's destructor has stricter attributes
|
||||
|
||||
```
|
||||
struct HasDtor
|
||||
{
|
||||
~this() {}
|
||||
}
|
||||
|
||||
struct Pure
|
||||
{
|
||||
HasDtor member;
|
||||
this(int) pure {} // Error: `this` has stricter attributes than its destructor (`pure`)
|
||||
}
|
||||
|
||||
struct Nothrow
|
||||
{
|
||||
HasDtor member;
|
||||
this(int) nothrow {} // Error: `this` has stricter attributes than its destructor (`nothrow`)
|
||||
}
|
||||
|
||||
struct NoGC
|
||||
{
|
||||
HasDtor member;
|
||||
this(int) @nogc {} // Error: `this` has stricter attributes than its destructor (`@nogc`)
|
||||
}
|
||||
|
||||
struct Safe
|
||||
{
|
||||
HasDtor member;
|
||||
this(int) @safe {} // Error: `this` has stricter attributes than its destructor (`@safe`)
|
||||
}
|
||||
```
|
|
@ -1,16 +0,0 @@
|
|||
Initializing a field with itself has been deprecated
|
||||
|
||||
This is to prevent a common mistake when a field and a parameter ought to have the same name,
|
||||
but one is misspelled where it's declared:
|
||||
|
||||
---
|
||||
struct S
|
||||
{
|
||||
int field;
|
||||
|
||||
this(int feild) // supposed to be: this(int field)
|
||||
{
|
||||
this.field = field; // equal to this.field = this.field
|
||||
}
|
||||
}
|
||||
---
|
|
@ -1,11 +0,0 @@
|
|||
An error is now given for subtracting pointers of different types
|
||||
|
||||
The following code now gives errors:
|
||||
```
|
||||
static assert(cast(void*)8 - cast(int*) 0 == 2L);
|
||||
static assert(cast(int*) 8 - cast(void*)0 == 8L);
|
||||
void test()
|
||||
{
|
||||
auto foo = (ushort*).init - (ubyte*).init;
|
||||
}
|
||||
```
|
|
@ -1,17 +0,0 @@
|
|||
An error is now issued for `in`/`out` contracts of `nothrow` functions that may throw
|
||||
|
||||
This used to issue a deprecation, it is now an error:
|
||||
```
|
||||
void test() nothrow
|
||||
in
|
||||
{
|
||||
throw new Exception(null); // Error: `in` contract may throw but function is marked as `nothrow`
|
||||
}
|
||||
out
|
||||
{
|
||||
throw new Exception(null); // Error: `out` contract may throw but function is marked as `nothrow`
|
||||
}
|
||||
do
|
||||
{
|
||||
}
|
||||
```
|
|
@ -1,40 +0,0 @@
|
|||
Typesafe variadic class parameters have been deprecated
|
||||
|
||||
This obscure feature allowed a limited form of implicit construction:
|
||||
|
||||
---
|
||||
void check(bool x, Exception e...)
|
||||
{
|
||||
if (!x)
|
||||
throw e;
|
||||
}
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
check(args.length > 1, "missing argument");
|
||||
}
|
||||
---
|
||||
|
||||
However, few uses of this feature have been found, and one project was actually mistakenly using it instead of the more common Typesafe variadic array parameter.
|
||||
Considering D doesn't support implicit construction and already has a confusing amount of different variadic parameter forms, it was decided to remove this feature.
|
||||
|
||||
As a corrective action, either call the constructor in the callee:
|
||||
|
||||
---
|
||||
void check(string msg)
|
||||
{
|
||||
if (!x)
|
||||
throw new Exception(msg);
|
||||
}
|
||||
---
|
||||
|
||||
Or let the caller construct the class instance:
|
||||
|
||||
---
|
||||
void check(bool x, Exception e);
|
||||
|
||||
void main(string[] args)
|
||||
{
|
||||
check(args.length > 1, new Exception("missing argument"));
|
||||
}
|
||||
---
|
|
@ -1,5 +0,0 @@
|
|||
Integers in `debug` or `version` statements have been removed from the language
|
||||
|
||||
These were deprecated in 2.101.
|
||||
Use `-debug=identifier` and `-version=identifier` instead for versions set on the command line,
|
||||
and likewise `version = identifier;` and `debug = identifier;` for versions set in code at global scope.
|
|
@ -1,123 +0,0 @@
|
|||
Many error messages have changed
|
||||
|
||||
Some changes have been made without being associated to a reported issue:
|
||||
|
||||
Error messages for `@safe` violations now consistently mention they are related to `@safe` functions (or default functions with `-preview=safer`).
|
||||
In general, function attributes that failed to infer have a more compact error message:
|
||||
|
||||
Before:
|
||||
$(CONSOLE
|
||||
app.d(8): Error: function `attributediagnostic_nothrow.gc1` is not `nothrow`
|
||||
app.d(2): which wasn't inferred `nothrow` because of:
|
||||
app.d(2): `object.Exception` is thrown but not caught
|
||||
)
|
||||
|
||||
After:
|
||||
$(CONSOLE
|
||||
app.d(8): Error: function `attributediagnostic_nothrow.gc1` is not `nothrow`
|
||||
app.d(2): and `object.Exception` being thrown but not caught makes it fail to infer `nothrow`
|
||||
)
|
||||
|
||||
Function literals are now referred to by their (truncated) function body, instead of the internal `__lambda` name.
|
||||
|
||||
---
|
||||
/*
|
||||
BEFORE:
|
||||
|
||||
../test/test_.d(3): Error: function literal `__lambda1()` is not callable using argument types `(int)`
|
||||
(() => 42)(1);
|
||||
^
|
||||
AFTER:
|
||||
|
||||
../test/test_.d(3): Error: function literal `() => 42` is not callable using argument types `(int)`
|
||||
(() => 42)(1);
|
||||
^
|
||||
*/
|
||||
---
|
||||
|
||||
Match levels are now mentioned on ambiguous overloads: [#20637](https://github.com/dlang/dmd/pull/20637)
|
||||
|
||||
Before:
|
||||
$(CONSOLE
|
||||
Error: `app.bar` called with argument types `(string)` matches both:
|
||||
)
|
||||
|
||||
After:
|
||||
$(CONSOLE
|
||||
Error: `app.bar` called with argument types `(string)` matches multiple overloads after implicit conversions:
|
||||
)
|
||||
|
||||
Error messages related to operator overloading have been improved.
|
||||
When the related template functions (`opUnary`, `opBinary`, `opBinaryRight`, `opOpAssign`, `opIndex`, `opSlice`)
|
||||
are missing, a suggestion to implement them is given.
|
||||
|
||||
When they do exist but fail to instantiate, the error from instantiation is shown.
|
||||
There's no longer a need to manually e.g. rewrite `s + 1` to `s.opBinary!"+"(1)` to diagnose the error.
|
||||
|
||||
---
|
||||
struct S {}
|
||||
|
||||
void main()
|
||||
{
|
||||
S s;
|
||||
const x = s[3 .. "4"];
|
||||
}
|
||||
---
|
||||
|
||||
Before:
|
||||
$(CONSOLE
|
||||
app.d(6): Error: no `[]` operator overload for type `S`
|
||||
)
|
||||
|
||||
After:
|
||||
$(CONSOLE
|
||||
app.d(6): Error: no `[3.."4"]` operator overload for type `S`
|
||||
app.d(1): perhaps define `auto opSlice(int lower, string upper) {}` for `app.S`
|
||||
)
|
||||
|
||||
---
|
||||
struct Str {}
|
||||
|
||||
struct Number
|
||||
{
|
||||
int x;
|
||||
int opBinary(string op : "+")(int rhs) => this.x + x;
|
||||
}
|
||||
|
||||
void f(Str str, Number number)
|
||||
{
|
||||
const s = str ~ "hey";
|
||||
const n = number + "oops";
|
||||
}
|
||||
---
|
||||
|
||||
Before:
|
||||
$(CONSOLE
|
||||
app.d(12): Error: incompatible types for `(str) ~ ("hey")`: `Str` and `string`
|
||||
const s = str ~ "hey";
|
||||
^
|
||||
app.d(13): Error: incompatible types for `(number) + ("oops")`: `Number` and `string`
|
||||
const n = number + "oops";
|
||||
)
|
||||
|
||||
After:
|
||||
$(CONSOLE
|
||||
app.d(12): Error: operator `~` is not defined for type `Str`
|
||||
const s = str ~ "hey";
|
||||
^
|
||||
app.d(2): perhaps overload the operator with `auto opBinary(string op : "~")(string rhs) {}`
|
||||
struct Str {}
|
||||
^
|
||||
app.d(13): Error: function `test_.Number.opBinary!"+".opBinary(int rhs)` is not callable using argument types `(string)`
|
||||
const n = number + "oops";
|
||||
^
|
||||
app.d(13): cannot pass argument `"oops"` of type `string` to parameter `int rhs`
|
||||
app.d(7): `opBinary` defined here
|
||||
int opBinary(string op : "+")(int rhs) => this.x + x;
|
||||
^
|
||||
)
|
||||
|
||||
Furthermore:
|
||||
|
||||
- D1 operator overloading functions (`opAdd`, `opDot`) are completely removed and no longer mentioned in error messages specifically.
|
||||
- Class allocators (`auto new() {}`) are not only a semantic error, but no longer parse.
|
|
@ -1,4 +0,0 @@
|
|||
The compiler now accepts `-extern-std=c++23`
|
||||
|
||||
The compiler now accepts c++23 as a supported standard for `-extern-std=`.
|
||||
Currently this only changes the value of `__traits(getTargetInfo, "cppStd")`.
|
|
@ -1,16 +0,0 @@
|
|||
Build time profiling has been added to DMD
|
||||
|
||||
The `-ftime-trace` switch that the LDC compiler already has, is now also available in dmd.
|
||||
It can be used to figure out which parts of your code take the longest to compile, so you can optimize your build times.
|
||||
|
||||
$(CONSOLE
|
||||
dmd -ftime-trace app.d
|
||||
)
|
||||
|
||||
This will output `app.o.time-trace`.
|
||||
|
||||
A different output file can be selected with `-ftime-trace-file=trace.json`.
|
||||
|
||||
The output is in Google Chrome's profiler format, which can be viewed in an interactive viewer like [ui.perfetto.dev](https://ui.perfetto.dev).
|
||||
|
||||
See also the YouTube tutorial [*Easily Reduce Build Times by Profiling the D Compiler*](https://www.youtube.com/watch?v=b8wZqU5t9vs).
|
|
@ -1,16 +0,0 @@
|
|||
New traits `getBitfieldOffset` and `getBitfieldWidth` for built-in bitfields
|
||||
|
||||
This completes the introspection capabilities of built-in bitfields. For example:
|
||||
|
||||
---
|
||||
struct S
|
||||
{
|
||||
int a,b;
|
||||
int :2, c:3;
|
||||
}
|
||||
|
||||
static assert(__traits(getBitfieldOffset, S.b) == 0);
|
||||
static assert(__traits(getBitfieldOffset, S.c) == 2);
|
||||
static assert(__traits(getBitfieldWidth, S.b) == 32);
|
||||
static assert(__traits(getBitfieldWidth, S.c) == 3);
|
||||
---
|
|
@ -1,3 +0,0 @@
|
|||
Using the compiler flag `-i` will now properly pick up C source files
|
||||
|
||||
Previously, you needed to manually include `*.c` source files, it now works just like with D files.
|
|
@ -1,25 +0,0 @@
|
|||
A pragma for ImportC allows to set `nothrow`, `@nogc` or `pure`
|
||||
|
||||
The following new pragma for ImportC allows to set default storage
|
||||
classes for function declarations:
|
||||
```c
|
||||
#pragma attribute(push, [storage classes...])
|
||||
```
|
||||
The storage classes `nothrow`, `nogc` and `pure` are supported.
|
||||
Unrecognized attributes are ignored.
|
||||
Enabling a default storage class affects all function declarations
|
||||
after the pragma until it is disabled with another pragma.
|
||||
Declarations in includes are also affected.
|
||||
The changed storage classes are pushed on a stack. The last change can
|
||||
be undone with the following pragma.
|
||||
The following example
|
||||
enables `@nogc` and `nothrow` for a library:
|
||||
|
||||
```c
|
||||
#pragma attribute(push, nogc, nothrow)
|
||||
#include <somelibrary.h>
|
||||
#pragma attribute(pop)
|
||||
```
|
||||
|
||||
This can also disable multiple default storage classes at the same time,
|
||||
if they were enabled with a single `#pragma attribute(push, ...)` directive.
|
|
@ -1,8 +0,0 @@
|
|||
Mixin templates can now use assignment syntax
|
||||
|
||||
Previously, giving a name to a mixed-in mixin template instance required putting the name at the end.
|
||||
Now, it can also go in front of the instantiation using assignment syntax.
|
||||
---
|
||||
mixin MyMixinTemplate!(Args) myName; // old style
|
||||
mixin myName = MyMixinTemplate!(Args); // new style
|
||||
---
|
|
@ -1,6 +0,0 @@
|
|||
Object file extensions `.o` and `.obj` are now accepted on all platforms
|
||||
|
||||
Accepting `.o` and `.obj` file extensions on all platforms makes DMD behave
|
||||
like Clang and other modern compilers. There is no point in
|
||||
discarding `*.o` or `*.obj` depending on the current operating system, as both extensions
|
||||
unambiguously denote object file.
|
|
@ -1,38 +0,0 @@
|
|||
Objective-C selectors are now automatically generated when not specified with `@selector`.
|
||||
|
||||
Additionally, the Objective-C selector generation rules have changed, following these steps:
|
||||
1. Functions marked with `@property` will generate `setXYZ:` for the setters.
|
||||
2. For property functions with names starting with `is`, that prefix will be stripped off in the setter.
|
||||
3. Selector generation now uses the names of the function parameters instead of their D-mangled types.
|
||||
|
||||
Selectors may still be specified with the `@selector` UDA, in which case it takes precedence over the
|
||||
automatically generated selectors.
|
||||
|
||||
These new rules apply both for `extern` and non-`extern` Objective-C classes and protocols.
|
||||
|
||||
---
|
||||
extern(Objective-C)
|
||||
extern class NSObject {
|
||||
static NSObject alloc(); // Generates as `alloc`
|
||||
NSObject init(); // Generates as `init`
|
||||
}
|
||||
|
||||
extern(Objective-C)
|
||||
class Fox : NSObject {
|
||||
bool fluffy;
|
||||
|
||||
@property bool isFluffy() => fluffy; // `isFluffy`
|
||||
@property void isFluffy(bool value) { fluffy = value; } // `setFluffy:`
|
||||
|
||||
void yip(int a) @selector("bark:") { // `bark:`
|
||||
// ...
|
||||
}
|
||||
|
||||
void doSomething(int a, int b, int c) { // `doSomething:b:c:`
|
||||
// ...
|
||||
}
|
||||
}
|
||||
---
|
||||
|
||||
These changes should not break any existing code because the automatic selector generation
|
||||
was not present before. And automatic selector generation only applies to `extern(Objective-C)` methods.
|
|
@ -1,15 +0,0 @@
|
|||
New compiler switch `-oq` for DMD
|
||||
|
||||
The switch gives fully qualified names to object files, preventing name conflicts when using the switch `-od`
|
||||
while compiling multiple modules with the same name, but inside different packages.
|
||||
The switch already existed in LDC, but is now in dmd as well.
|
||||
|
||||
Example:
|
||||
|
||||
$(CONSOLE
|
||||
dmd -c -oq -od=. app.d util/app.d misc/app.d
|
||||
)
|
||||
|
||||
This will output `app.obj`, `util.app.obj`, and `misc.app.obj`, instead of just `app.obj`.
|
||||
|
||||
The switch `-oq` also applies to other outputs, such as Ddoc (`-D -Dd=.`) and `.di` header generation (`-H -Hd=.`).
|
|
@ -1,20 +0,0 @@
|
|||
Added Placement New Expression
|
||||
|
||||
Placement `new` explicitly provides the storage for `new` expression to initialize
|
||||
with the newly created value, rather than using the GC.
|
||||
|
||||
---
|
||||
struct S
|
||||
{
|
||||
float d;
|
||||
int i;
|
||||
char c;
|
||||
}
|
||||
|
||||
void main() @system @nogc
|
||||
{
|
||||
S s;
|
||||
S* p = new (s) S(3.14, 42, 'X'); // place new object into s
|
||||
assert(p.i == 42 && p.c == 'X');
|
||||
}
|
||||
---
|
|
@ -1,13 +0,0 @@
|
|||
Postfix type qualifier method attributes for `-H` and `-D`
|
||||
|
||||
The `.di` interface file generation and Ddoc output will now have type qualifier
|
||||
attributes placed after the parameter list for methods (and constructors).
|
||||
This avoids confusion with the return type.
|
||||
|
||||
---
|
||||
struct S
|
||||
{
|
||||
const int f(); // before
|
||||
int f() const; // now
|
||||
}
|
||||
---
|
|
@ -1,8 +0,0 @@
|
|||
The folder *samples* has been removed from DMD installations
|
||||
|
||||
Every DMD release has included a folder with small D code examples.
|
||||
These examples are quite old, and not a good representation of modern D.
|
||||
They're also hard to discover, since D compilers are often installed through an installer or package manager.
|
||||
|
||||
Since there are better resources available online nowadays, these samples have
|
||||
been moved to the [undeaD](https://github.com/dlang/undeaD) repository.
|
|
@ -1,40 +0,0 @@
|
|||
New keyword `__rvalue`
|
||||
|
||||
The newly added primary expression of the form `__rvalue(expression)`
|
||||
evaluates to `expression`, except that it is treated as an rvalue,
|
||||
even if would be an lvalue otherwise.
|
||||
|
||||
Overloads on `ref`:
|
||||
```
|
||||
foo( S s); // selected if the argument is an rvalue
|
||||
foo(ref S s); // selected if the argument is an lvalue
|
||||
|
||||
S s;
|
||||
S bar();
|
||||
...
|
||||
foo(s); // selects foo(ref S)
|
||||
foo(bar()); // selects foo(S)
|
||||
```
|
||||
With this change:
|
||||
```
|
||||
foo(__rvalue(s)); // selects foo(S)
|
||||
```
|
||||
This also applies to constructors and assignments, meaning move constructors and
|
||||
move assignments are enabled. Moving instead of copying can be much more resource
|
||||
efficient, as, say, a string can be moved rather than copied/deleted.
|
||||
|
||||
A moved object will still be destructed, so take that into account when moving
|
||||
a field - set it to a benign value that can be destructed.
|
||||
|
||||
`__rvalue` may also be used as an attribute on a function which returns by ref
|
||||
to declare that the result should be treated as an rvalue at the callsite:
|
||||
```
|
||||
ref T move(T)(return ref T source) __rvalue
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
S s;
|
||||
S t = move(s); // call expression rewritten as: S t = __rvalue(move(s))
|
||||
```
|
||||
This is used as an internal tool to implement library primitives such as `move` and `forward`.
|
|
@ -1,22 +0,0 @@
|
|||
Add `-preview=safer` switch for safety checking on unattributed functions
|
||||
|
||||
All the checks currently enabled in `@safe` code, that are easily fixed (as in
|
||||
the fix is constrained to the function), will be enabled in `-preview=safer` code.
|
||||
|
||||
Code not easily fixed, such as calls to `@system` or unattributed functions, will
|
||||
be allowed as before.
|
||||
|
||||
---
|
||||
void f();
|
||||
@system void g();
|
||||
|
||||
void main()
|
||||
{
|
||||
int* p;
|
||||
p++; // Error, pointer arithmetic
|
||||
f(); // allowed
|
||||
g(); // allowed
|
||||
}
|
||||
---
|
||||
|
||||
For more information, see [this document](https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md).
|
|
@ -1,18 +0,0 @@
|
|||
Shortened method syntax can now be used in constructors
|
||||
|
||||
This used to raise an error (cannot return expression from constructor), but is now supported:
|
||||
|
||||
---
|
||||
struct Number
|
||||
{
|
||||
int x;
|
||||
|
||||
void vf(int);
|
||||
this(int x) => vf(x);
|
||||
this(float x) => this(cast(int) x);
|
||||
}
|
||||
---
|
||||
|
||||
The expression body must be a `this`/`super` call or have type `void`.
|
||||
|
||||
Postblits and destructors already supported shortened method syntax because they return `void`.
|
|
@ -1,7 +0,0 @@
|
|||
Add Windows BCrypt bindings under `core.sys.windows.bcrypt`
|
||||
|
||||
Adds full [BCrypt API](https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/) bindings
|
||||
to the Windows-specific system bindings.
|
||||
|
||||
The Windows-specific bindings under `core.sys.windows.sdkddkver` and `core.sys.windows.w32api`
|
||||
have also been updated in order to facilitate the creation of the BCrypt bindings.
|
|
@ -1,5 +0,0 @@
|
|||
Remove `criticalRegionLock`
|
||||
|
||||
The `criticalRegionLock` feature suffer from a serious design flaw: $(LINK https://issues.dlang.org/show_bug.cgi?id=24741)
|
||||
|
||||
It turns out it is not used, so rather than fixing the flaw, the feature was removed.
|
|
@ -1,7 +0,0 @@
|
|||
Adds `expect`, `likely`, `unlikely`, and `trap` to `core.builtins`
|
||||
|
||||
Adds the functions `expect` and `likely`/`unlikely` for branch and value hints for the LDC/GDC compilers.
|
||||
DMD ignores these hints.
|
||||
|
||||
Adds the function `trap` to be lowered to the target-dependent trap instruction.
|
||||
If the target does not have a trap instruction, this intrinsic will be lowered to a call of the `abort` function.
|
|
@ -1,65 +0,0 @@
|
|||
New segfault handler showing backtraces for null access / call stack overflow on linux
|
||||
|
||||
While buffer overflows are usually caught by array bounds checks, there are still other situations where a segmentation fault occurs in D programs:
|
||||
|
||||
- `null` pointer dereference
|
||||
- Corrupted or dangling pointer dereference in `@system` code
|
||||
- Call stack overflow (infinite recursion)
|
||||
|
||||
These result in an uninformative runtime error such as:
|
||||
|
||||
$(CONSOLE
|
||||
[1] 37856 segmentation fault (core dumped) ./app
|
||||
)
|
||||
|
||||
In order to find the cause of the error, the program needs to be run again in a debugger like GDB.
|
||||
|
||||
There is the `registerMemoryErrorHandler` function in `etc.linux.memoryerror`, which catches `SIGSEGV` signals and transforms them into a thrown `InvalidPointerError`, providing a better message.
|
||||
However, it doesn't work on call stack overflow, because it uses stack memory itself, so the segfault handler segfaults.
|
||||
It also relies on inline assembly, limiting it to the x86 architecture.
|
||||
|
||||
A new function `registerMemoryAssertHandler` has been introduced, which does handle stack overflow by setting up an [altstack](https://man7.org/linux/man-pages/man2/sigaltstack.2.html).
|
||||
It uses `assert(0)` instead of throwing an `Error` object, so the result corresponds to the chosen `-checkaction` setting.
|
||||
|
||||
Example:
|
||||
|
||||
---
|
||||
void main()
|
||||
{
|
||||
version (linux)
|
||||
{
|
||||
import etc.linux.memoryerror;
|
||||
registerMemoryAssertHandler();
|
||||
}
|
||||
int* p = null;
|
||||
int* q = cast(int*) 0xDEADBEEF;
|
||||
|
||||
// int a = *p; // segmentation fault: null pointer read/write operation
|
||||
// int b = *q; // segmentation fault: invalid pointer read/write operation
|
||||
recurse(); // segmentation fault: call stack overflow
|
||||
}
|
||||
|
||||
void recurse()
|
||||
{
|
||||
recurse();
|
||||
}
|
||||
---
|
||||
|
||||
Output with `dmd -g -run app.d`:
|
||||
|
||||
$(CONSOLE
|
||||
core.exception.AssertError@src/etc/linux/memoryerror.d(82): segmentation fault: call stack overflow
|
||||
$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)
|
||||
src/core/exception.d:587 onAssertErrorMsg [0x58e270d2802d]
|
||||
src/core/exception.d:803 _d_assert_msg [0x58e270d1fb64]
|
||||
src/etc/linux/memoryerror.d:82 _d_handleSignalAssert [0x58e270d1f48d]
|
||||
??:? [0x7004139e876f]
|
||||
./app.d:16 void scratch.recurse() [0x58e270d1d757]
|
||||
./app.d:18 void scratch.recurse() [0x58e270d1d75c]
|
||||
./app.d:18 void scratch.recurse() [0x58e270d1d75c]
|
||||
./app.d:18 void scratch.recurse() [0x58e270d1d75c]
|
||||
./app.d:18 void scratch.recurse() [0x58e270d1d75c]
|
||||
...
|
||||
...
|
||||
...
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue