Bug 71182 - [6 Regression] parser.c cp_lexer_previous_token sanitizer detects member call on null pointer
Summary: [6 Regression] parser.c cp_lexer_previous_token sanitizer detects member call...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.0
: P3 normal
Target Milestone: 6.4
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2016-05-18 20:00 UTC by Vittorio Zecca
Modified: 2017-01-18 16:26 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-11-30 00:00:00


Attachments
gcc7-pr71182.patch (512 bytes, patch)
2017-01-03 10:50 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Vittorio Zecca 2016-05-18 20:00:55 UTC
// ../../gcc7/gcc/cp/parser.c:766:7: runtime error: member call on null pointer of type 'struct vec'
class A {
  template <typename> void As();
};
template <typename T> class B : A {
  void f() {
    A *g ;
    g ? g->As<T>() : nullptr;
  }
};
Comment 1 Markus Trippelsdorf 2016-11-30 09:10:20 UTC
Confirmed. Started with r231293:

commit 3d27a0fa5bfc6af64855917aa6f644d2386f8300
Author: dmalcolm <dmalcolm@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Fri Dec 4 18:09:54 2015 +0000

    C++ FE: expression ranges

markus@x4 tmp % UBSAN_OPTIONS=print_stacktrace=1 /var/tmp/gcc_ubsan/usr/local/bin/g++ -c parse.ii
../../gcc/gcc/cp/parser.c:768:7: runtime error: member call on null pointer of type 'struct vec'
    #0 0xb5dd4f in cp_lexer_previous_token ../../gcc/gcc/cp/parser.c:768
    #1 0xb5dd4f in cp_parser_postfix_dot_deref_expression ../../gcc/gcc/cp/parser.c:7451
    #2 0xb6b22d in cp_parser_postfix_expression ../../gcc/gcc/cp/parser.c:7047
    #3 0xb70da1 in cp_parser_unary_expression ../../gcc/gcc/cp/parser.c:8099
    #4 0xb74cf8 in cp_parser_cast_expression ../../gcc/gcc/cp/parser.c:8776
    #5 0xb76faa in cp_parser_binary_expression ../../gcc/gcc/cp/parser.c:8877
    #6 0xb79d40 in cp_parser_assignment_expression ../../gcc/gcc/cp/parser.c:9164
    #7 0xb88fc0 in cp_parser_expression ../../gcc/gcc/cp/parser.c:9333
    #8 0xb79f99 in cp_parser_question_colon_clause ../../gcc/gcc/cp/parser.c:9107
    #9 0xb79f99 in cp_parser_assignment_expression ../../gcc/gcc/cp/parser.c:9170
    #10 0xb88fc0 in cp_parser_expression ../../gcc/gcc/cp/parser.c:9333
    #11 0xb9c9b0 in cp_parser_expression_statement ../../gcc/gcc/cp/parser.c:10877
    #12 0xb44d29 in cp_parser_statement ../../gcc/gcc/cp/parser.c:10693
    #13 0xb497a0 in cp_parser_statement_seq_opt ../../gcc/gcc/cp/parser.c:11019
    #14 0xb49aa4 in cp_parser_compound_statement ../../gcc/gcc/cp/parser.c:10973
    #15 0xb96988 in cp_parser_function_body ../../gcc/gcc/cp/parser.c:21357
    #16 0xb96988 in cp_parser_ctor_initializer_opt_and_function_body ../../gcc/gcc/cp/parser.c:21393
    #17 0xbb9fa2 in cp_parser_function_definition_after_declarator ../../gcc/gcc/cp/parser.c:26151
    #18 0xbbb144 in cp_parser_late_parsing_for_member ../../gcc/gcc/cp/parser.c:27033
    #19 0xb2e24f in cp_parser_class_specifier_1 ../../gcc/gcc/cp/parser.c:22244
    #20 0xb34f42 in cp_parser_class_specifier ../../gcc/gcc/cp/parser.c:22270
    #21 0xb34f42 in cp_parser_type_specifier ../../gcc/gcc/cp/parser.c:16386
    #22 0xb3780c in cp_parser_decl_specifier_seq ../../gcc/gcc/cp/parser.c:13303
    #23 0xb38d5a in cp_parser_single_declaration ../../gcc/gcc/cp/parser.c:26521
    #24 0xbb78ee in cp_parser_template_declaration_after_parameters ../../gcc/gcc/cp/parser.c:26212
    #25 0xbb6b9a in cp_parser_explicit_template_declaration ../../gcc/gcc/cp/parser.c:26448
    #26 0xbb6b9a in cp_parser_template_declaration_after_export ../../gcc/gcc/cp/parser.c:26466
    #27 0xb3a349 in cp_parser_declaration ../../gcc/gcc/cp/parser.c:12445
    #28 0xbec445 in cp_parser_declaration_seq_opt ../../gcc/gcc/cp/parser.c:12364
    #29 0xbecfee in cp_parser_translation_unit ../../gcc/gcc/cp/parser.c:4368
    #30 0xbecfee in c_parse_file() ../../gcc/gcc/cp/parser.c:38262
    #31 0x1101f4b in c_common_parse_file() ../../gcc/gcc/c-family/c-opts.c:1098
    #32 0x24f370a in compile_file ../../gcc/gcc/toplev.c:463
    #33 0x64bea4 in do_compile ../../gcc/gcc/toplev.c:1983
    #34 0x64bea4 in toplev::main(int, char**) ../../gcc/gcc/toplev.c:2117
    #35 0x64e4d6 in main ../../gcc/gcc/main.c:39
    #36 0x7f2977921310 in __libc_start_main ../csu/libc-start.c:286
    #37 0x64e8e9 in _start (/var/tmp/gcc_ubsan/usr/local/libexec/gcc/x86_64-pc-linux-gnu/7.0.0/cc1plus+0x64e8e9)
Comment 2 Markus Trippelsdorf 2016-11-30 09:13:25 UTC
  760 static inline cp_token *                                                                                                                                                     
  761 cp_lexer_previous_token (cp_lexer *lexer)                                                                                                                                    
  762 {                                                                                                                                                                            
  763   cp_token_position tp = cp_lexer_previous_token_position (lexer);                                                                                                           
  764                                                                                                                                                                              
  765   /* Skip past purged tokens.  */                                                                                                                                            
  766   while (tp->purged_p)                                                                                                                                                       
  767     {                                                                                                                                                                        
  768       gcc_assert (tp != lexer->buffer->address ());                                                                                                                          
  769       tp--;                                                                                                                                                                  
  770     }                                                                                                                                                                        
  771                                                                                                                                                                              
  772   return cp_lexer_token_at (lexer, tp);                                                                                                                                      
  773 }
Comment 3 Richard Biener 2016-12-06 13:10:39 UTC
Can't reproduce on trunk or GCC 6 branch.  What options are required?
Comment 4 Markus Trippelsdorf 2016-12-06 13:19:05 UTC
(In reply to Richard Biener from comment #3)
> Can't reproduce on trunk or GCC 6 branch.  What options are required?

You need to use an -fsanitize=undefined instrumented compiler.
No options required.
Comment 5 Markus Trippelsdorf 2016-12-06 13:37:07 UTC
(gdb) l
763       cp_token_position tp = cp_lexer_previous_token_position (lexer);
764
765       /* Skip past purged tokens.  */
766       while (tp->purged_p)
767         {
768           gcc_assert (tp != lexer->buffer->address ());
769           tp--;
770         }
771
772       return cp_lexer_token_at (lexer, tp);
(gdb) p *lexer
$1 = {
  buffer = 0x0,
  last_token = 0x7ffff7e0c2f8,
  next_token = 0x7ffff7e0c298,
  saved_tokens = {
    m_vec = 0x92c6b20
  },
  next = 0x7ffff5f96480,
  debugging_p = false,
  in_pragma = false
}
Comment 6 Markus Trippelsdorf 2016-12-06 13:46:20 UTC
So, perhaps:
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 08f5f9e52ef2..f430af97fdf1 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -765,7 +765,7 @@ cp_lexer_previous_token (cp_lexer *lexer)
   /* Skip past purged tokens.  */
   while (tp->purged_p)
     {
-      gcc_assert (tp != lexer->buffer->address ());
+      gcc_assert (!lexer->buffer || tp != lexer->buffer->address ());
       tp--;
     }
Comment 7 Jakub Jelinek 2017-01-03 10:50:28 UTC
Created attachment 40445 [details]
gcc7-pr71182.patch

That or use vec_safe_address for a vector that is not always non-NULL.
I'll test this version, let Jason choose what he wants.
Comment 8 Jakub Jelinek 2017-01-04 20:05:46 UTC
Author: jakub
Date: Wed Jan  4 20:05:14 2017
New Revision: 244070

URL: https://gcc.gnu.org/viewcvs?rev=244070&root=gcc&view=rev
Log:
	PR c++/71182
	* parser.c (cp_lexer_previous_token): Use vec_safe_address in the
	assertion, as lexer->buffer may be NULL.

	* g++.dg/cpp0x/pr71182.C: New test.

Added:
    trunk/gcc/testsuite/g++.dg/cpp0x/pr71182.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/parser.c
    trunk/gcc/testsuite/ChangeLog
Comment 9 Jakub Jelinek 2017-01-04 20:14:05 UTC
Fixed on the trunk so far.
Comment 10 Jakub Jelinek 2017-01-17 20:30:58 UTC
Author: jakub
Date: Tue Jan 17 20:30:25 2017
New Revision: 244550

URL: https://gcc.gnu.org/viewcvs?rev=244550&root=gcc&view=rev
Log:
	Backported from mainline
	2017-01-04  Jakub Jelinek  <jakub@redhat.com>

	PR c++/71182
	* parser.c (cp_lexer_previous_token): Use vec_safe_address in the
	assertion, as lexer->buffer may be NULL.

	* g++.dg/cpp0x/pr71182.C: New test.

Added:
    branches/gcc-6-branch/gcc/testsuite/g++.dg/cpp0x/pr71182.C
Modified:
    branches/gcc-6-branch/gcc/cp/ChangeLog
    branches/gcc-6-branch/gcc/cp/parser.c
    branches/gcc-6-branch/gcc/testsuite/ChangeLog
Comment 11 Jakub Jelinek 2017-01-18 16:26:30 UTC
Fixed for 6.4+.