From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17393 invoked by alias); 6 Aug 2008 15:20:45 -0000 Received: (qmail 17301 invoked by uid 22791); 6 Aug 2008 15:20:41 -0000 X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 06 Aug 2008 15:19:46 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id m76FJi3p013085 for ; Wed, 6 Aug 2008 11:19:44 -0400 Received: from pobox.stuttgart.redhat.com (pobox.stuttgart.redhat.com [172.16.2.10]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id m76FJbMr021509 for ; Wed, 6 Aug 2008 11:19:38 -0400 Received: from host0.dyn.jankratochvil.net (sebastian-int.corp.redhat.com [172.16.52.221]) by pobox.stuttgart.redhat.com (8.13.1/8.13.1) with ESMTP id m76FJZmS005124 for ; Wed, 6 Aug 2008 11:19:36 -0400 Received: from host0.dyn.jankratochvil.net (localhost [127.0.0.1]) by host0.dyn.jankratochvil.net (8.14.3/8.14.2) with ESMTP id m76FJYn9000863; Wed, 6 Aug 2008 17:19:34 +0200 Received: (from jkratoch@localhost) by host0.dyn.jankratochvil.net (8.14.3/8.14.2/Submit) id m76FJXLN000857; Wed, 6 Aug 2008 17:19:33 +0200 Date: Wed, 06 Aug 2008 15:20:00 -0000 From: Jan Kratochvil To: gdb-patches@sources.redhat.com Cc: Vinay Sridhar , Daniel Jacobowitz , luisgpm@linux.vnet.ibm.com, uweigand@de.ibm.com Subject: Re: [patch] Re: Accessing tls variables across files causes a bug Message-ID: <20080806151933.GA32530@host0.dyn.jankratochvil.net> References: <1217480020.4755.1.camel@vinaysridhar.in.ibm.com> <20080802171807.GA2755@host0.dyn.jankratochvil.net> <1217925527.3658.41.camel@vinaysridhar.in.ibm.com> <20080805122118.GB17219@caradoc.them.org> <1218021410.13466.4.camel@vinaysridhar.in.ibm.com> <20080806114241.GA18923@host0.dyn.jankratochvil.net> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="3V7upXqbjpZ4EhLz" Content-Disposition: inline In-Reply-To: <20080806114241.GA18923@host0.dyn.jankratochvil.net> User-Agent: Mutt/1.5.18 (2008-05-17) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-08/txt/msg00117.txt.bz2 --3V7upXqbjpZ4EhLz Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 746 On Wed, 06 Aug 2008 13:42:41 +0200, Jan Kratochvil wrote: > Another possibility is that LOC_UNRESOLVED may no longer be needed for recent > gcc debuginfos always(?) containting `DW_AT_location's, therefore we would not > have to deal with `minimal_symbol's in this case at all. Attached. It has no regressions on x86_64, Fedora gcc-4.3.1-6.x86_64 (but gcc-4.3 has GDB regressions against gcc-4.1). Also tried there are no regressions by check//unix/-gstabs+ (although the three new TLS testcases FAIL there). I do not fully grok why psymtabs were created for DW_AT_type DIEs with no DW_AT_location. IMO (DW_AT_location || DW_AT_const_value) is the right condition (DW_AT_const_value requirement was found by a testsuite run). Regards, Jan --3V7upXqbjpZ4EhLz Content-Type: text/plain; charset=us-ascii Content-Disposition: inline; filename="gdb-remove-LOC_UNRESOLVED.patch" Content-length: 18518 2008-08-06 Jan Kratochvil Fix resolving external references to TLS variables. * ada-lang.c (ada_add_block_symbols): Remove LOC_UNRESOLVED. * ax-gdb.c (gen_var_ref): Likewise. * gen_var_ref (symbol_read_needs_frame, read_var_value): Likewise. * m2-exp.y (yylex): Likewise. * printcmd.c (address_info): Likewise. * symmisc.c (print_symbol, print_partial_symbols): Likewise. * symtab.h (enum address_class): Likewise. * tracepoint.c (collect_symbol, scope_info): Likewise. * mi/mi-cmd-stack.c (list_args_or_locals): Likewise. * stabsread.c (scan_file_globals): Complain even on LOC_STATIC symbols. Set such symbols to LOC_UNDEF instead of LOC_UNRESOLVED. * dwarf2read.c (struct partial_die_info): Remove the field HAS_TYPE. New field HAS_CONST_VALUE. (add_partial_symbol) : HAS_TYPE condition removed. HAS_CONST_VALUE condition added. Comment updated. (read_partial_die) : Case removed. (read_partial_die) : New case. (new_symbol): Remove setting LOC_UNRESOLVED. Comment updated. 2008-08-06 Jan Kratochvil Update for removed LOC_UNRESOLVED, test resolving external references to TLS variables. * gdb.dwarf2/dw2-noloc.S: New variable "optloc". * gdb.dwarf2/dw2-noloc.exp: Test the new variable "optloc". Update the current message for the variable "noloc". * gdb.threads/tls.exp: New tests to print A_THREAD_LOCAL and FILE2_THREAD_LOCAL. (testfile2, srcfile2): New variables. * gdb.threads/tls.c (file2_thread_local) (function_referencing_file2_thread_local): New. * gdb.threads/tls2.c: New file. --- gdb/ada-lang.c 21 Jul 2008 16:47:10 -0000 1.151 +++ gdb/ada-lang.c 6 Aug 2008 15:13:51 -0000 @@ -5211,9 +5211,7 @@ ada_add_block_symbols (struct obstack *o SYMBOL_DOMAIN (sym), domain) && wild_match (name, name_len, SYMBOL_LINKAGE_NAME (sym))) { - if (SYMBOL_CLASS (sym) == LOC_UNRESOLVED) - continue; - else if (SYMBOL_IS_ARGUMENT (sym)) + if (SYMBOL_IS_ARGUMENT (sym)) arg_sym = sym; else { @@ -5236,17 +5234,14 @@ ada_add_block_symbols (struct obstack *o if (cmp == 0 && is_name_suffix (SYMBOL_LINKAGE_NAME (sym) + name_len)) { - if (SYMBOL_CLASS (sym) != LOC_UNRESOLVED) + if (SYMBOL_IS_ARGUMENT (sym)) + arg_sym = sym; + else { - if (SYMBOL_IS_ARGUMENT (sym)) - arg_sym = sym; - else - { - found_sym = 1; - add_defn_to_vec (obstackp, - fixup_symbol_section (sym, objfile), - block); - } + found_sym = 1; + add_defn_to_vec (obstackp, + fixup_symbol_section (sym, objfile), + block); } } } @@ -5284,17 +5279,14 @@ ada_add_block_symbols (struct obstack *o if (cmp == 0 && is_name_suffix (SYMBOL_LINKAGE_NAME (sym) + name_len + 5)) { - if (SYMBOL_CLASS (sym) != LOC_UNRESOLVED) + if (SYMBOL_IS_ARGUMENT (sym)) + arg_sym = sym; + else { - if (SYMBOL_IS_ARGUMENT (sym)) - arg_sym = sym; - else - { - found_sym = 1; - add_defn_to_vec (obstackp, - fixup_symbol_section (sym, objfile), - block); - } + found_sym = 1; + add_defn_to_vec (obstackp, + fixup_symbol_section (sym, objfile), + block); } } } --- gdb/ax-gdb.c 27 May 2008 19:29:51 -0000 1.44 +++ gdb/ax-gdb.c 6 Aug 2008 15:13:53 -0000 @@ -596,19 +596,6 @@ gen_var_ref (struct agent_expr *ax, stru value->kind = axs_lvalue_memory; break; - case LOC_UNRESOLVED: - { - struct minimal_symbol *msym - = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (var), NULL, NULL); - if (!msym) - error (_("Couldn't resolve symbol `%s'."), SYMBOL_PRINT_NAME (var)); - - /* Push the address of the variable. */ - ax_const_l (ax, SYMBOL_VALUE_ADDRESS (msym)); - value->kind = axs_lvalue_memory; - } - break; - case LOC_COMPUTED: /* FIXME: cagney/2004-01-26: It should be possible to unconditionally call the SYMBOL_OPS method when available. --- gdb/dwarf2read.c 27 Jun 2008 17:56:47 -0000 1.267 +++ gdb/dwarf2read.c 6 Aug 2008 15:14:01 -0000 @@ -462,7 +462,7 @@ struct partial_die_info unsigned int has_children : 1; unsigned int is_external : 1; unsigned int is_declaration : 1; - unsigned int has_type : 1; + unsigned int has_const_value : 1; unsigned int has_specification : 1; unsigned int has_stmt_list : 1; unsigned int has_pc_info : 1; @@ -1988,18 +1988,17 @@ add_partial_symbol (struct partial_die_i Don't enter into the minimal symbol tables as there is a minimal symbol table entry from the ELF symbols already. Enter into partial symbol table if it has a location - descriptor or a type. - If the location descriptor is missing, new_symbol will create - a LOC_UNRESOLVED symbol, the address of the variable will then - be determined from the minimal symbol table whenever the variable - is referenced. + descriptor. It may have a type but still if it has neither + location descriptor nor it is a constant value it must be just an + `extern' declaration we are not interested in. Optimized out + variables will have a 0-length location descriptor. The address for the partial symbol table entry is not used by GDB, but it comes in handy for debugging partial symbol table building. */ if (pdi->locdesc) addr = decode_locdesc (pdi->locdesc, cu); - if (pdi->locdesc || pdi->has_type) + if (pdi->locdesc || pdi->has_const_value) psym = add_psymbol_to_list (actual_name, strlen (actual_name), VAR_DOMAIN, LOC_STATIC, &objfile->global_psymbols, @@ -5837,8 +5836,8 @@ read_partial_die (struct partial_die_inf case DW_AT_declaration: part_die->is_declaration = DW_UNSND (&attr); break; - case DW_AT_type: - part_die->has_type = 1; + case DW_AT_const_value: + part_die->has_const_value = 1; break; case DW_AT_abstract_origin: case DW_AT_specification: @@ -7486,19 +7485,15 @@ new_symbol (struct die_info *die, struct } else { - /* We do not know the address of this symbol. - If it is an external symbol and we have type information - for it, enter the symbol as a LOC_UNRESOLVED symbol. - The address of the variable will then be determined from - the minimal symbol table whenever the variable is - referenced. */ - attr2 = dwarf2_attr (die, DW_AT_external, cu); - if (attr2 && (DW_UNSND (attr2) != 0) - && dwarf2_attr (die, DW_AT_type, cu) != NULL) - { - SYMBOL_CLASS (sym) = LOC_UNRESOLVED; - add_symbol_to_list (sym, &global_symbols); - } + /* We do not know the address of this symbol. If it is an + external symbol and we have type information + for it, we could enter the symbol as a LOC_UNRESOLVED symbol. + The address of the variable could then be determined from the + minimal symbol table whenever the variable is referenced. + Just it needs an exception in the code whenever we get + LOC_UNRESOLVED and some places miss it, fortunately recent GCC + puts DW_AT_location everywhere so this workaround is no longer + needed. */ } break; case DW_TAG_formal_parameter: --- gdb/findvar.c 15 Jul 2008 17:53:11 -0000 1.115 +++ gdb/findvar.c 6 Aug 2008 15:14:02 -0000 @@ -371,7 +371,6 @@ symbol_read_needs_frame (struct symbol * case LOC_BLOCK: case LOC_CONST_BYTES: - case LOC_UNRESOLVED: case LOC_OPTIMIZED_OUT: return 0; } @@ -533,21 +532,6 @@ read_var_value (struct symbol *var, stru return 0; return SYMBOL_OPS (var)->read_variable (var, frame); - case LOC_UNRESOLVED: - { - struct minimal_symbol *msym; - - msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (var), NULL, NULL); - if (msym == NULL) - return 0; - if (overlay_debugging) - addr = symbol_overlayed_address (SYMBOL_VALUE_ADDRESS (msym), - SYMBOL_BFD_SECTION (msym)); - else - addr = SYMBOL_VALUE_ADDRESS (msym); - } - break; - case LOC_OPTIMIZED_OUT: VALUE_LVAL (v) = not_lval; set_value_optimized_out (v, 1); --- gdb/m2-exp.y 27 May 2008 19:29:51 -0000 1.21 +++ gdb/m2-exp.y 6 Aug 2008 15:14:02 -0000 @@ -1059,7 +1059,6 @@ yylex () error("internal: Undefined class in m2lex()"); case LOC_LABEL: - case LOC_UNRESOLVED: error("internal: Unforseen case in m2lex()"); default: --- gdb/printcmd.c 6 Jun 2008 20:58:08 -0000 1.127 +++ gdb/printcmd.c 6 Aug 2008 15:14:05 -0000 @@ -1169,30 +1169,6 @@ address_info (char *exp, int from_tty) } break; - case LOC_UNRESOLVED: - { - struct minimal_symbol *msym; - - msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (sym), NULL, NULL); - if (msym == NULL) - printf_filtered ("unresolved"); - else - { - section = SYMBOL_BFD_SECTION (msym); - printf_filtered (_("static storage at address ")); - load_addr = SYMBOL_VALUE_ADDRESS (msym); - fputs_filtered (paddress (load_addr), gdb_stdout); - if (section_is_overlay (section)) - { - load_addr = overlay_unmapped_address (load_addr, section); - printf_filtered (_(",\n -- loaded at ")); - fputs_filtered (paddress (load_addr), gdb_stdout); - printf_filtered (_(" in overlay section %s"), section->name); - } - } - } - break; - case LOC_OPTIMIZED_OUT: printf_filtered (_("optimized out")); break; --- gdb/stabsread.c 27 May 2008 19:29:51 -0000 1.108 +++ gdb/stabsread.c 6 Aug 2008 15:14:08 -0000 @@ -4501,7 +4501,7 @@ scan_file_globals (struct objfile *objfi } /* Change the storage class of any remaining unresolved globals to - LOC_UNRESOLVED and remove them from the chain. */ + LOC_UNDEF and remove them from the chain. */ for (hash = 0; hash < HASHSIZE; hash++) { sym = global_sym_chain[hash]; @@ -4514,13 +4514,11 @@ scan_file_globals (struct objfile *objfi to address zero. */ SYMBOL_VALUE_ADDRESS (prev) = 0; + SYMBOL_CLASS (prev) = LOC_UNDEF; /* Complain about unresolved common block symbols. */ - if (SYMBOL_CLASS (prev) == LOC_STATIC) - SYMBOL_CLASS (prev) = LOC_UNRESOLVED; - else - complaint (&symfile_complaints, - _("%s: common block `%s' from global_sym_chain unresolved"), - objfile->name, DEPRECATED_SYMBOL_NAME (prev)); + complaint (&symfile_complaints, + _("%s: common block `%s' from global_sym_chain unresolved"), + objfile->name, DEPRECATED_SYMBOL_NAME (prev)); } } memset (global_sym_chain, 0, sizeof (global_sym_chain)); --- gdb/symmisc.c 27 May 2008 19:29:51 -0000 1.53 +++ gdb/symmisc.c 6 Aug 2008 15:14:09 -0000 @@ -701,10 +701,6 @@ print_symbol (void *args) fprintf_filtered (outfile, "computed at runtime"); break; - case LOC_UNRESOLVED: - fprintf_filtered (outfile, "unresolved"); - break; - case LOC_OPTIMIZED_OUT: fprintf_filtered (outfile, "optimized out"); break; @@ -837,9 +833,6 @@ print_partial_symbols (struct partial_sy case LOC_CONST_BYTES: fputs_filtered ("constant bytes", outfile); break; - case LOC_UNRESOLVED: - fputs_filtered ("unresolved", outfile); - break; case LOC_OPTIMIZED_OUT: fputs_filtered ("optimized out", outfile); break; --- gdb/symtab.h 27 May 2008 19:29:51 -0000 1.128 +++ gdb/symtab.h 6 Aug 2008 15:14:12 -0000 @@ -476,18 +476,6 @@ enum address_class LOC_CONST_BYTES, - /* Value is at fixed address, but the address of the variable has - to be determined from the minimal symbol table whenever the - variable is referenced. - This happens if debugging information for a global symbol is - emitted and the corresponding minimal symbol is defined - in another object file or runtime common storage. - The linker might even remove the minimal symbol if the global - symbol is never referenced, in which case the symbol remains - unresolved. */ - - LOC_UNRESOLVED, - /* The variable does not actually exist in the program. The value is ignored. */ --- gdb/tracepoint.c 25 Jul 2008 16:12:03 -0000 1.107 +++ gdb/tracepoint.c 6 Aug 2008 15:14:14 -0000 @@ -1289,10 +1289,6 @@ collect_symbol (struct collection_list * } add_memrange (collect, reg, offset, len); break; - case LOC_UNRESOLVED: - printf_filtered ("Don't know LOC_UNRESOLVED %s\n", - DEPRECATED_SYMBOL_NAME (sym)); - break; case LOC_OPTIMIZED_OUT: printf_filtered ("%s has been optimized out of existence.\n", DEPRECATED_SYMBOL_NAME (sym)); @@ -2457,17 +2453,6 @@ scope_info (char *args, int from_tty) printf_filtered ("a function at address "); printf_filtered ("%s", paddress (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)))); break; - case LOC_UNRESOLVED: - msym = lookup_minimal_symbol (DEPRECATED_SYMBOL_NAME (sym), - NULL, NULL); - if (msym == NULL) - printf_filtered ("Unresolved Static"); - else - { - printf_filtered ("static storage at address "); - printf_filtered ("%s", paddress (SYMBOL_VALUE_ADDRESS (msym))); - } - break; case LOC_OPTIMIZED_OUT: printf_filtered ("optimized out.\n"); continue; --- gdb/mi/mi-cmd-stack.c 25 Jun 2008 15:15:42 -0000 1.41 +++ gdb/mi/mi-cmd-stack.c 6 Aug 2008 15:14:15 -0000 @@ -238,7 +238,6 @@ list_args_or_locals (int locals, int val case LOC_LABEL: /* local label */ case LOC_BLOCK: /* local function */ case LOC_CONST_BYTES: /* loc. byte seq. */ - case LOC_UNRESOLVED: /* unresolved static */ case LOC_OPTIMIZED_OUT: /* optimized out */ print_me = 0; break; --- gdb/testsuite/gdb.dwarf2/dw2-noloc.S 1 Jan 2008 22:53:19 -0000 1.3 +++ gdb/testsuite/gdb.dwarf2/dw2-noloc.S 6 Aug 2008 15:14:15 -0000 @@ -69,6 +69,12 @@ func_cu1: .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */ .byte 1 /* DW_AT_external */ + .uleb128 5 /* Abbrev: DW_TAG_variable */ + .ascii "optloc\0" /* DW_AT_name */ + .4byte .Ltype_int-.Lcu1_begin /* DW_AT_type */ + .byte 1 /* DW_AT_external */ + .byte 0 /* DW_AT_location: length */ + .byte 0 /* End of children of CU */ .Lcu1_end: @@ -140,6 +146,20 @@ func_cu1: .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ + .uleb128 5 /* Abbrev code */ + .uleb128 0x34 /* DW_TAG_variable */ + .byte 0 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x3f /* DW_AT_external */ + .uleb128 0xc /* DW_FORM_flag */ + .uleb128 0x2 /* DW_AT_location */ + .uleb128 0xa /* DW_FORM_block1 */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ .byte 0x0 /* Terminator */ --- gdb/testsuite/gdb.dwarf2/dw2-noloc.exp 1 Jan 2008 22:53:19 -0000 1.3 +++ gdb/testsuite/gdb.dwarf2/dw2-noloc.exp 6 Aug 2008 15:14:15 -0000 @@ -45,4 +45,5 @@ gdb_start gdb_reinitialize_dir $srcdir/$subdir gdb_load ${binfile} -gdb_test "print noloc" "Address of symbol \"noloc\" is unknown." "print noloc" +gdb_test "print noloc" "No symbol \"noloc\" in current context." "print noloc" +gdb_test "print optloc" " = " "print optloc" --- gdb/testsuite/gdb.threads/tls.c 29 Jul 2003 21:51:25 -0000 1.2 +++ gdb/testsuite/gdb.threads/tls.c 6 Aug 2008 15:14:17 -0000 @@ -20,6 +20,9 @@ __thread int a_thread_local; __thread int another_thread_local; +/* psymtabs->symtabs resolving check. */ +extern __thread int file2_thread_local; + /* Global variable just for info addr in gdb. */ int a_global; @@ -119,6 +122,12 @@ void *spin( vp ) } void +function_referencing_file2_thread_local (void) +{ + file2_thread_local = file2_thread_local; +} + +void do_pass() { int i; --- gdb/testsuite/gdb.threads/tls.exp 6 Aug 2008 12:52:08 -0000 1.9 +++ gdb/testsuite/gdb.threads/tls.exp 6 Aug 2008 15:14:17 -0000 @@ -15,7 +15,9 @@ # along with this program. If not, see . */ set testfile tls +set testfile2 tls2 set srcfile ${testfile}.c +set srcfile2 ${testfile2}.c set binfile ${objdir}/${subdir}/${testfile} if [istarget "*-*-linux"] then { @@ -24,7 +26,7 @@ if [istarget "*-*-linux"] then { set target_cflags "" } -if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } { +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile} ${srcdir}/${subdir}/${srcfile2}" "${binfile}" executable [list debug "incdir=${objdir}"]] != "" } { return -1 } @@ -284,6 +286,15 @@ gdb_test "info address a_global" \ setup_kfail "gdb/1294" "*-*-*" gdb_test "info address me" ".*me.*is a variable at offset.*" "info address me" + +# Test LOC_UNRESOLVED references for the `extern' variables. + +gdb_test "p a_thread_local" " = \[0-9\]+" +# Here it could crash with: Cannot access memory at address 0x0 +gdb_test "p file2_thread_local" " = \[0-9\]+" +# Here it could crash with: Cannot access memory at address 0x0 +gdb_test "p a_thread_local" " = \[0-9\]+" + # Done! # gdb_exit --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gdb/testsuite/gdb.threads/tls2.c 6 Aug 2008 15:14:17 -0000 @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Please email any bugs, comments, and/or additions to this file to: + bug-gdb@prep.ai.mit.edu */ + +extern __thread int a_thread_local; +__thread int file2_thread_local; + +void +function_referencing_a_thread_local (void) +{ + a_thread_local = a_thread_local; +} --3V7upXqbjpZ4EhLz--