Fix Issue 12118 - Modify immutable data using throw (#14706)

* Fix Issue 12118 - Modify immutable data using throw

* Change immutable test to const

* Deprecate throwing any qualified type

* Allow throw shared as std.concurrency does that

* Use static this instead of static const for test

* Only allow single shared qualifier or none

* Add changelog

* Disallow throwing shared objects too

* Update changelog/dmd.throw-qualifier.dd

Co-authored-by: Razvan Nitu <razvan.nitu1305@gmail.com>

---------

Co-authored-by: Razvan Nitu <razvan.nitu1305@gmail.com>
This commit is contained in:
Nick Treleaven 2023-03-13 15:42:18 +00:00 committed by GitHub
parent c69d3d4e0c
commit 7d6ac55712
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 4 deletions

View file

@ -0,0 +1,11 @@
Throwing qualified objects is now deprecated
Previously, an `immutable`, `const`, `inout` or `shared` exception could be
thrown and then caught in an unqualified `catch (Exception e)` clause.
That breaks type safety.
Throwing a qualified object is now deprecated. This helps to prevent
possible mutation of an immutable object in a `catch` clause.
The runtime also modifies a thrown object (e.g. to contain a stack
trace) which can violate `const` or `immutable` objects. Throwing
qualified objects has been deprecated for this reason also.

View file

@ -3796,7 +3796,13 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
exp = checkGC(sc, exp);
if (exp.op == EXP.error)
return false;
if (!exp.type.isNaked())
{
// @@@DEPRECATED_2.112@@@
// Deprecated in 2.102, change into an error & return false in 2.112
exp.loc.deprecation("cannot throw object of qualified type `%s`", exp.type.toChars());
//return false;
}
checkThrowEscape(sc, exp, false);
ClassDeclaration cd = exp.type.toBasetype().isClassHandle();

View file

@ -1,7 +1,9 @@
/*
TEST_OUTPUT:
---
fail_compilation/ice10651.d(11): Error: can only throw class objects derived from `Throwable`, not type `int*`
fail_compilation/ice10651.d(13): Error: can only throw class objects derived from `Throwable`, not type `int*`
fail_compilation/ice10651.d(19): Deprecation: cannot throw object of qualified type `immutable(Exception)`
fail_compilation/ice10651.d(20): Deprecation: cannot throw object of qualified type `const(Dummy)`
---
*/
@ -10,3 +12,20 @@ void main()
alias T = int;
throw new T(); // ICE
}
void f()
{
immutable c = new Exception("");
if (c) throw c;
throw new const Dummy([]);
}
class Dummy: Exception
{
int[] data;
@safe pure nothrow this(immutable int[] data) immutable
{
super("Dummy");
this.data = data;
}
}

View file

@ -154,7 +154,13 @@ void testDeleteWithoutCpp()
class ThrowingChildD : ChildD
{
static immutable ex = new Exception("STOP");
static Exception ex;
static this()
{
ex = new Exception("STOP");
}
~this()
{
throw ex;

View file

@ -24,7 +24,7 @@ class Abc : Throwable
{
printf("foo 1\n");
x |= 4;
throw this;
throw cast() this;
printf("foo 2\n");
x |= 8;
}