La méthode utilisée par libstdc++ est de comparer un pointeur de fonction. Un type = une fonction = une adresse différente. À chaque ajout d'une valeur
dans le any, il y a l'adresse de &une_function<T> en plus.
boost::ctti se sert de PRETTY_FUNCTION ou équivalent comme identifiant.
Merci ! Effectivement c'est bien vu comme astuce.
typeid n'est pas une fonction qui retourne quelque chose. C'est une expression (c'est un mot-clé du langage). Mais le résultat est une lvalue avec un static storage duration.
Justement. Donc ce n'est jamais censé être nul.
HS : utilises std::cout en C++. Et active les warnings, tu devrais avoir un avertissement sur le cast en void*.
J'aime pas cout. Et bon, dans le programmde preuve c'était voulu, pour afficher l'adresse de la référence renvoyée; j'aurais fait comment avec cout ?
En vrai j'ai commencé par constater ce retour de référence nulle avec gdb dans mon logiciel concret; en l'occurence celui-ci, python34.h, autour de la ligne 339.
| template<> struct PyConverter<any> {
static PyObject* inCast (const any& a) {
if (a.empty() || isoftype(a, nullptr_t)) Py_RETURN_NONE;
#define T(...) else if (isoftype(a,##__VA_ARGS__)) return PyConverter<__VA_ARGS__>::inCast( any_cast<__VA_ARGS__>(a) );
T(int) T(std::wstring) T(std::string) T(bool)
T(vector<tstring>) T(vector<int>)
T(pair<tstring,int>) T(pair<vector<tstring>,int>) T(pair<int,int>)
#undef T
else Py_RETURN_NONE;
}
|
Donc a priori, pas possible que cela retourne a une reference nulle. Il faudrait voir l'assembleur généré qui produit ce résultat. Avec mingw, c'est l'option -S.
Voici ce que ça donne pour mon petit programme de test :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 | .section .rdata,"dr"
__ZStL19piecewise_construct:
.space 1
.def ___main; .scl 2; .type 32; .endef
LC0:
.ascii "int\0"
LC1:
.ascii "%s: %p\12\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB6255:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
call ___main
movl $__ZTIi, 8(%esp)
movl $LC0, 4(%esp)
movl $LC1, (%esp)
call _printf
movl $0, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE6255:
.ident "GCC: (GNU) 5.3.0"
.def _printf; .scl 2; .type 32; .endef
|
Dans ce code rien n'a l'air d'être anormal pour ce que j'en connais. Par contre il ne prouve rien, on n'a pas la définition de $__ZTIi, qui pourrait très bien être nul.
Le bug doit être dans libstdc++-6.dll. C'est de là que la valeur est importée.
Voyons voir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 | Exports from libstdc++-6.dll
5243 exported name(s), 5243 export addresse(s). Ordinal base is 1.
Sorted by Name:
RVA Ord. Hint Name
-------- ---- ---- ----
000BD068 1 0000 _ZGVNSt10moneypunctIcLb0EE2idE
000BD070 2 0001 _ZGVNSt10moneypunctIcLb1EE2idE
...
000C68C8 4685 124C _ZTISt9strstream
000C68D4 4686 124D _ZTISt9time_base
000C68DC 4687 124E _ZTISt9type_info
901C0000 4688 124F _ZTIa
901C0000 4689 1250 _ZTIb
901C0000 4690 1251 _ZTIc
901C0000 4691 1252 _ZTId
901C0000 4692 1253 _ZTIe
901C0000 4693 1254 _ZTIf
901C0000 4694 1255 _ZTIg
901C0000 4695 1256 _ZTIh
901C0000 4696 1257 _ZTIi
901C0000 4697 1258 _ZTIj
901C0000 4698 1259 _ZTIl
901C0000 4699 125A _ZTIm
901C0000 4700 125B _ZTIs
901C0000 4701 125C _ZTIt
000C68E4 4702 125D _ZTIv
901C0000 4703 125E _ZTIw
901C0000 4704 125F _ZTIx
901C0000 4705 1260 _ZTIy
000C6920 4706 1261 _ZTSN10__cxxabiv116__enum_type_infoE
000C6960 4707 1262 _ZTSN10__cxxabiv117__array_type_infoE
000C69A0 4708 1263 _ZTSN10__cxxabiv117__class_type_infoE
...
|
Tous les typeinfo des types primitifs (les _ZTI?) ont la même référence: 901C0000. C'est louche.
J'en déduis qu'ils sont tous nuls.
Et je le prouve :
| HINSTANCE dll = LoadLibrary("LIBSTDC++-6.DLL");
void* data = (void*)GetProcAddress(dll, "__ZTIi");
printf("Last error = %d\n", GetLastError());
printf("dll=%p\n", dll);
printf("data=%p\n", data);
|
Résultat :
| Last error = 0
dll=6FE40000
data=00000000
|
Si GetProcAddress m'avait retourné NULL parce que le symbole n'était pas trouvé dans la DLL, alors GetLastError() m'aurait retourné l'erreur 127, cf. MSDN
Maintenant qu'on est convaincu que c'est effectivement bien un bug du compilateur, c'est quoi la suite ?
JE suppose qu'il ne sera jamais corrigé vu le nombre ahurissant qu'ils en ont déjà ?
Si c'est comme les bugs de Firefox… En même temps à leur place si j'étais développeur en chef d'un mégaprojet, j'en aurais probablement rien à f### du bug à la con d'un bouzeux; et je les comprends, ils ont autre chose à faire.