https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88937

--- Comment #4 from David Malcolm <dmalcolm at gcc dot gnu.org> ---
It's clearly wrong to access token->val.node for token->type == CPP_STRING and
token->type == CPP_HEADER_NAME.  It's effectively casting the length of the
header name to a (cpp_hashnode *).

For reference, this was introduced in r215752 (2014-10-01) in gcc 5.

Patch review was:
  "[PATCH C++] - SD-6 Implementation Part 1 - __has_include."
    https://gcc.gnu.org/ml/gcc-patches/2014-09/msg00083.html

later revised to:
  "Re: [PATCH C++] - SD-6 Implementation Part 1 - __has_include."
    https://gcc.gnu.org/ml/gcc-patches/2014-09/msg02533.html
    as "patch_feature_test_1b"
      https://gcc.gnu.org/ml/gcc-patches/2014-09/txtMPDgWoRx_D.txt
  (approved by Jason here:
    https://gcc.gnu.org/ml/gcc-patches/2014-09/msg02645.html )

The comment makes no sense in the given context.

It looks to me like this was copied-and-pasted from parse_defined, which also
has:

      /* A possible controlling macro of the form #if !defined ().
         _cpp_parse_expr checks there was no other junk on the line.  */
      pfile->mi_ind_cmacro = node;

where it *does* make sense; it's handling a CPP_NAME i.e. a "defined
(SOME_NAME)",
and recording the macro SOME_NAME, for handling that syntax for the
header-file-guard idiom.

Given that __has_include is purely checking for the presence of files (rather
than their inclusion), this seems meaningless here, and I think it's probably
best to delete that "node" handling from parse_has_include.

That said, I've been attempting and failing to turn this into a
read-through-the-corrupt-pointer crasher: _cpp_parse_expr, resets the
mi_ind_cmacro back, unless we have !has_include("foo.h")

1426      /* The controlling macro expression is only valid if we called lex 3
1427         times: <!> <defined expression> and <EOF>.  push_conditional ()
1428         checks that we are at top-of-file.  */
1429      if (pfile->mi_ind_cmacro && !(saw_leading_not && lex_count == 3))
1430        pfile->mi_ind_cmacro = 0;

and the "macro" is only saved in push_conditional if 

2130      if (pfile->mi_valid && pfile->mi_cmacro == 0)
2131        ifs->mi_cmacro = cmacro;

and pfile->mi_valid is being cleared in my test cases.

Hence I don't *think* it's currently possible for the bogus pointer to be
dereferenced.

Reply via email to