[D] Fix occasional undefined behaviour with inheritance hierarchies

Particularly when using virtual inheritance as the pointers weren't
correctly upcast from derived class to base class when stored in the
base's proxy class.

Fixes commented out test code in cpp11_std_unique_ptr_runme
and li_std_auto_ptr_runme D tests.
This commit is contained in:
William S Fulton 2022-08-05 19:36:54 +01:00
commit 910fd1e3cf
8 changed files with 73 additions and 12 deletions

View file

@ -7,6 +7,11 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.1.0 (in progress) Version 4.1.0 (in progress)
=========================== ===========================
2022-08-05: wsfulton
[D] Fix occasional undefined behaviour with inheritance hierarchies, particularly
when using virtual inheritance as the pointers weren't correctly upcast from derived
class to base class when stored in the base's proxy class.
2022-08-05: wsfulton 2022-08-05: wsfulton
[D] Add support for std::unique_ptr in std_unique_ptr.i. [D] Add support for std::unique_ptr in std_unique_ptr.i.
Add support for std::auto_ptr in std_auto_ptr.i. Add support for std::auto_ptr in std_auto_ptr.i.

View file

@ -10,6 +10,7 @@
%inline %{ %inline %{
#include <memory> #include <memory>
#include <string> #include <string>
//#include <iostream>
#include "swig_examples_lock.h" #include "swig_examples_lock.h"
class Klass { class Klass {
@ -53,8 +54,18 @@ struct KlassInheritance : virtual Klass {
} }
}; };
std::string useKlassRawPtr(Klass* k) {
// std::cout << "useKlassRawPtr " << std::hex << (Klass*)k << std::endl;
std::string s(k->getLabel());
// std::cout << "useKlassRawPtr string: " << s << std::endl;
return s;
}
std::string takeKlassUniquePtr(std::unique_ptr<Klass> k) { std::string takeKlassUniquePtr(std::unique_ptr<Klass> k) {
return std::string(k->getLabel()); // std::cout << "takeKlassUniquePtr " << std::hex << (Klass*)k.get() << std::endl;
std::string s(k->getLabel());
// std::cout << "takeKlassUniquePtr string: " << s << std::endl;
return s;
} }
bool is_nullptr(Klass *p) { bool is_nullptr(Klass *p) {

View file

@ -13,6 +13,16 @@ void checkCount(int expected_count) {
} }
void main() { void main() {
// Test raw pointer handling involving virtual inheritance
{
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1);
string s = useKlassRawPtr(kini);
if (s != "KlassInheritanceInput")
throw new Exception("Incorrect string: " ~ s);
}
checkCount(0);
// unique_ptr as input // unique_ptr as input
{ {
scope Klass kin = new Klass("KlassInput"); scope Klass kin = new Klass("KlassInput");
@ -65,7 +75,6 @@ void main() {
} }
checkCount(0); checkCount(0);
/*
{ {
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1); checkCount(1);
@ -77,7 +86,6 @@ void main() {
throw new Exception("is_nullptr failed"); throw new Exception("is_nullptr failed");
} // dispose should not fail, even though already deleted } // dispose should not fail, even though already deleted
checkCount(0); checkCount(0);
*/
// unique_ptr as output // unique_ptr as output
Klass k1 = makeKlassUniquePtr("first"); Klass k1 = makeKlassUniquePtr("first");

View file

@ -13,6 +13,16 @@ void checkCount(int expected_count) {
} }
void main() { void main() {
// Test raw pointer handling involving virtual inheritance
{
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1);
string s = useKlassRawPtr(kini);
if (s != "KlassInheritanceInput")
throw new Exception("Incorrect string: " ~ s);
}
checkCount(0);
// unique_ptr as input // unique_ptr as input
{ {
scope Klass kin = new Klass("KlassInput"); scope Klass kin = new Klass("KlassInput");
@ -65,7 +75,6 @@ void main() {
} }
checkCount(0); checkCount(0);
/*
{ {
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1); checkCount(1);
@ -77,7 +86,6 @@ void main() {
throw new Exception("is_nullptr failed"); throw new Exception("is_nullptr failed");
} // dispose should not fail, even though already deleted } // dispose should not fail, even though already deleted
checkCount(0); checkCount(0);
*/
// unique_ptr as output // unique_ptr as output
Klass k1 = makeKlassUniquePtr("first"); Klass k1 = makeKlassUniquePtr("first");

View file

@ -13,6 +13,16 @@ void checkCount(int expected_count) {
} }
void main() { void main() {
// Test raw pointer handling involving virtual inheritance
{
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1);
string s = useKlassRawPtr(kini);
if (s != "KlassInheritanceInput")
throw new Exception("Incorrect string: " ~ s);
}
checkCount(0);
// auto_ptr as input // auto_ptr as input
{ {
scope Klass kin = new Klass("KlassInput"); scope Klass kin = new Klass("KlassInput");
@ -65,7 +75,6 @@ void main() {
} }
checkCount(0); checkCount(0);
/*
{ {
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1); checkCount(1);
@ -77,7 +86,6 @@ void main() {
throw new Exception("is_nullptr failed"); throw new Exception("is_nullptr failed");
} // dispose should not fail, even though already deleted } // dispose should not fail, even though already deleted
checkCount(0); checkCount(0);
*/
// auto_ptr as output // auto_ptr as output
Klass k1 = makeKlassAutoPtr("first"); Klass k1 = makeKlassAutoPtr("first");

View file

@ -13,6 +13,17 @@ void checkCount(int expected_count) {
} }
void main() { void main() {
// Test raw pointer handling involving virtual inheritance
{
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1);
string s = useKlassRawPtr(kini);
checkCount(1);
if (s != "KlassInheritanceInput")
throw new Exception("Incorrect string: " ~ s);
}
checkCount(0);
// auto_ptr as input // auto_ptr as input
{ {
scope Klass kin = new Klass("KlassInput"); scope Klass kin = new Klass("KlassInput");
@ -65,7 +76,6 @@ void main() {
} }
checkCount(0); checkCount(0);
/*
{ {
scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput"); scope KlassInheritance kini = new KlassInheritance("KlassInheritanceInput");
checkCount(1); checkCount(1);
@ -77,7 +87,6 @@ void main() {
throw new Exception("is_nullptr failed"); throw new Exception("is_nullptr failed");
} // dispose should not fail, even though already deleted } // dispose should not fail, even though already deleted
checkCount(0); checkCount(0);
*/
// auto_ptr as output // auto_ptr as output
Klass k1 = makeKlassAutoPtr("first"); Klass k1 = makeKlassAutoPtr("first");

View file

@ -15,6 +15,7 @@
#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) || defined(SWIGJAVASCRIPT) || defined(SWIGD) #if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON) || defined(SWIGRUBY) || defined(SWIGPERL) || defined(SWIGTCL) || defined(SWIGOCTAVE) || defined(SWIGJAVASCRIPT) || defined(SWIGD)
%include "std_string.i" %include "std_string.i"
//#include <iostream>
%include "std_auto_ptr.i" %include "std_auto_ptr.i"
%auto_ptr(Klass) %auto_ptr(Klass)
@ -100,10 +101,21 @@ struct KlassInheritance : virtual Klass {
} }
}; };
std::string takeKlassAutoPtr(std::auto_ptr<Klass> k) { std::string useKlassRawPtr(Klass* k) {
return std::string(k->getLabel()); // std::cout << "useKlassRawPtr " << std::hex << (Klass*)k << std::endl;
std::string s(k->getLabel());
// std::cout << "useKlassRawPtr string: " << s << std::endl;
return s;
} }
std::string takeKlassAutoPtr(std::auto_ptr<Klass> k) {
// std::cout << "takeKlassAutoPtr " << std::hex << (Klass*)k.get() << std::endl;
std::string s(k->getLabel());
// std::cout << "takeKlassAutoPtr string: " << s << std::endl;
return s;
}
bool is_nullptr(Klass *p) { bool is_nullptr(Klass *p) {
return p == 0; return p == 0;
} }

View file

@ -3402,7 +3402,7 @@ private:
} else { } else {
Printv(upcasts_code, Printv(upcasts_code,
"SWIGEXPORT ", baseclassname, " * ", upcast_wrapper_name, "SWIGEXPORT ", baseclassname, " * ", upcast_wrapper_name,
"(", baseclassname, " *objectRef) {\n", "(", classname, " *objectRef) {\n",
" return (", baseclassname, " *)objectRef;\n" " return (", baseclassname, " *)objectRef;\n"
"}\n", "}\n",
"\n", NIL); "\n", NIL);