Merge from Chromium at DEPS revision 265802

This commit was generated by merge_to_master.py.

Change-Id: If68565edc37f9a7c05edc557edd8ece69c9f31d3
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index 9408613..4707950 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -825,6 +825,7 @@
       cflags_objcc = ['$cflags_cc'] + \
                      self.xcode_settings.GetCflagsObjCC(config_name)
     elif self.flavor == 'win':
+      asmflags = self.msvs_settings.GetAsmflags(config_name)
       cflags = self.msvs_settings.GetCflags(config_name)
       cflags_c = self.msvs_settings.GetCflagsC(config_name)
       cflags_cc = self.msvs_settings.GetCflagsCC(config_name)
@@ -859,6 +860,8 @@
     self.WriteVariableList(ninja_file, 'defines',
                            [Define(d, self.flavor) for d in defines])
     if self.flavor == 'win':
+      self.WriteVariableList(ninja_file, 'asmflags',
+                             map(self.ExpandSpecial, asmflags))
       self.WriteVariableList(ninja_file, 'rcflags',
           [QuoteShellArgument(self.ExpandSpecial(f), self.flavor)
            for f in self.msvs_settings.GetRcflags(config_name,
@@ -1889,7 +1892,7 @@
       'asm',
       description='ASM $in',
       command=('%s gyp-win-tool asm-wrapper '
-               '$arch $asm $defines $includes /c /Fo $out $in' %
+               '$arch $asm $defines $includes $asmflags /c /Fo $out $in' %
                sys.executable))
 
   if flavor != 'mac' and flavor != 'win':
diff --git a/pylib/gyp/msvs_emulation.py b/pylib/gyp/msvs_emulation.py
index 6b5dfc2..63593a4 100644
--- a/pylib/gyp/msvs_emulation.py
+++ b/pylib/gyp/msvs_emulation.py
@@ -345,6 +345,15 @@
     else:
       return None
 
+  def GetAsmflags(self, config):
+    """Returns the flags that need to be added to ml invocations."""
+    config = self._TargetConfig(config)
+    asmflags = []
+    safeseh = self._Setting(('MASM', 'UseSafeExceptionHandlers'), config)
+    if safeseh == 'true':
+      asmflags.append('/safeseh')
+    return asmflags
+
   def GetCflags(self, config):
     """Returns the flags that need to be added to .c and .cc compilations."""
     config = self._TargetConfig(config)
@@ -528,6 +537,7 @@
     ld('Profile', map={'true': '/PROFILE'})
     ld('LargeAddressAware',
         map={'1': ':NO', '2': ''}, prefix='/LARGEADDRESSAWARE')
+    ld('ImageHasSafeExceptionHandlers', map={'true': '/SAFESEH'})
     # TODO(scottmg): This should sort of be somewhere else (not really a flag).
     ld('AdditionalDependencies', prefix='')
 
diff --git a/test/cflags/gyptest-cflags.py b/test/cflags/gyptest-cflags.py
index f897a70..0a87ed8 100755
--- a/test/cflags/gyptest-cflags.py
+++ b/test/cflags/gyptest-cflags.py
@@ -5,41 +5,25 @@
 # found in the LICENSE file.
 
 """
-Verifies build of an executable with C++ define specified by a gyp define, and
-the use of the environment during regeneration when the gyp file changes.
+Verifies the use of the environment during regeneration when the gyp file
+changes, specifically via build of an executable with C preprocessor
+definition specified by CFLAGS.
+
+In this test, gyp and build both run in same local environment.
 """
 
-import os
-import sys
 import TestGyp
 
-env_stack = []
+# CPPFLAGS works in ninja but not make; CFLAGS works in both
+FORMATS = ('make', 'ninja')
 
+test = TestGyp.TestGyp(formats=FORMATS)
 
-def PushEnv():
-  env_copy = os.environ.copy()
-  env_stack.append(env_copy)
-
-def PopEnv():
-  os.environ.clear()
-  os.environ.update(env_stack.pop())
-
-formats = ['make', 'ninja']
-
-test = TestGyp.TestGyp(formats=formats)
-
-try:
-  PushEnv()
-  os.environ['CFLAGS'] = ''
-  os.environ['GYP_CROSSCOMPILE'] = '1'
+# First set CFLAGS to blank in case the platform doesn't support unsetenv.
+with TestGyp.LocalEnv({'CFLAGS': '',
+                       'GYP_CROSSCOMPILE': '1'}):
   test.run_gyp('cflags.gyp')
   test.build('cflags.gyp')
-finally:
-  # We clear the environ after calling gyp.  When the auto-regeneration happens,
-  # the same define should be reused anyway.  Reset to empty string first in
-  # case the platform doesn't support unsetenv.
-  PopEnv()
-
 
 expect = """FOO not defined\n"""
 test.run_built_executable('cflags', stdout=expect)
@@ -47,18 +31,10 @@
 
 test.sleep()
 
-try:
-  PushEnv()
-  os.environ['CFLAGS'] = '-DFOO=1'
-  os.environ['GYP_CROSSCOMPILE'] = '1'
+with TestGyp.LocalEnv({'CFLAGS': '-DFOO=1',
+                       'GYP_CROSSCOMPILE': '1'}):
   test.run_gyp('cflags.gyp')
   test.build('cflags.gyp')
-finally:
-  # We clear the environ after calling gyp.  When the auto-regeneration happens,
-  # the same define should be reused anyway.  Reset to empty string first in
-  # case the platform doesn't support unsetenv.
-  PopEnv()
-
 
 expect = """FOO defined\n"""
 test.run_built_executable('cflags', stdout=expect)
@@ -69,34 +45,18 @@
 
 test.sleep()
 
-try:
-  PushEnv()
-  os.environ['CFLAGS'] = ''
+with TestGyp.LocalEnv({'CFLAGS': ''}):
   test.run_gyp('cflags.gyp')
   test.build('cflags.gyp')
-finally:
-  # We clear the environ after calling gyp.  When the auto-regeneration happens,
-  # the same define should be reused anyway.  Reset to empty string first in
-  # case the platform doesn't support unsetenv.
-  PopEnv()
-
 
 expect = """FOO not defined\n"""
 test.run_built_executable('cflags', stdout=expect)
 
 test.sleep()
 
-try:
-  PushEnv()
-  os.environ['CFLAGS'] = '-DFOO=1'
+with TestGyp.LocalEnv({'CFLAGS': '-DFOO=1'}):
   test.run_gyp('cflags.gyp')
   test.build('cflags.gyp')
-finally:
-  # We clear the environ after calling gyp.  When the auto-regeneration happens,
-  # the same define should be reused anyway.  Reset to empty string first in
-  # case the platform doesn't support unsetenv.
-  PopEnv()
-
 
 expect = """FOO defined\n"""
 test.run_built_executable('cflags', stdout=expect)
diff --git a/test/cxxflags/cxxflags.cc b/test/cxxflags/cxxflags.cc
index c1e2452..44b299c 100644
--- a/test/cxxflags/cxxflags.cc
+++ b/test/cxxflags/cxxflags.cc
@@ -6,10 +6,10 @@
 
 int main(int argc, char *argv[])
 {
-#ifdef __OPTIMIZE__
-  printf("Using an optimization flag\n");
+#ifdef ABC
+  printf("With define\n");
 #else
-  printf("Using no optimization flag\n");
+  printf("No define\n");
 #endif
   return 0;
 }
diff --git a/test/cxxflags/cxxflags.gyp b/test/cxxflags/cxxflags.gyp
index 24d883a..a082d49 100644
--- a/test/cxxflags/cxxflags.gyp
+++ b/test/cxxflags/cxxflags.gyp
@@ -7,7 +7,6 @@
     {
       'target_name': 'cxxflags',
       'type': 'executable',
-      'opt': '-Os',
       'sources': [
         'cxxflags.cc',
       ],
diff --git a/test/cxxflags/gyptest-cxxflags.py b/test/cxxflags/gyptest-cxxflags.py
index 70142e7..117a180 100755
--- a/test/cxxflags/gyptest-cxxflags.py
+++ b/test/cxxflags/gyptest-cxxflags.py
@@ -5,60 +5,40 @@
 # found in the LICENSE file.
 
 """
-Verifies build of an executable with C++ define specified by a gyp define, and
-the use of the environment during regeneration when the gyp file changes.
+Verifies the use of the environment during regeneration when the gyp file
+changes, specifically via build of an executable with C++ flags specified by
+CXXFLAGS.
+
+In this test, gyp happens within a local environment, but build outside of it.
 """
 
-import os
 import TestGyp
 
-env_stack = []
+FORMATS = ('ninja',)
 
+test = TestGyp.TestGyp(formats=FORMATS)
 
-def PushEnv():
-  env_copy = os.environ.copy()
-  env_stack.append(env_copy)
-
-def PopEnv():
-  os.eniron=env_stack.pop()
-
-# Regenerating build files when a gyp file changes is currently only supported
-# by the make generator.
-test = TestGyp.TestGyp(formats=['make'])
-
-try:
-  PushEnv()
-  os.environ['CXXFLAGS'] = '-O0'
+# We reset the environ after calling gyp. When the auto-regeneration happens,
+# the same define should be reused anyway.
+with TestGyp.LocalEnv({'CXXFLAGS': ''}):
   test.run_gyp('cxxflags.gyp')
-finally:
-  # We clear the environ after calling gyp.  When the auto-regeneration happens,
-  # the same define should be reused anyway.  Reset to empty string first in
-  # case the platform doesn't support unsetenv.
-  PopEnv()
 
 test.build('cxxflags.gyp')
 
 expect = """\
-Using no optimization flag
+No define
 """
 test.run_built_executable('cxxflags', stdout=expect)
 
 test.sleep()
 
-try:
-  PushEnv()
-  os.environ['CXXFLAGS'] = '-O2'
+with TestGyp.LocalEnv({'CXXFLAGS': '-DABC'}):
   test.run_gyp('cxxflags.gyp')
-finally:
-  # We clear the environ after calling gyp.  When the auto-regeneration happens,
-  # the same define should be reused anyway.  Reset to empty string first in
-  # case the platform doesn't support unsetenv.
-  PopEnv()
 
 test.build('cxxflags.gyp')
 
 expect = """\
-Using an optimization flag
+With define
 """
 test.run_built_executable('cxxflags', stdout=expect)
 
diff --git a/test/lib/TestGyp.py b/test/lib/TestGyp.py
index 306bf3d..36b6281 100644
--- a/test/lib/TestGyp.py
+++ b/test/lib/TestGyp.py
@@ -7,6 +7,7 @@
 """
 
 import collections
+from contextlib import contextmanager
 import itertools
 import os
 import re
@@ -24,9 +25,10 @@
   'TestGyp',
 ])
 
+
 def remove_debug_line_numbers(contents):
   """Function to remove the line numbers from the debug output
-  of gyp and thus remove the exremem fragility of the stdout
+  of gyp and thus reduce the extreme fragility of the stdout
   comparison tests.
   """
   lines = contents.splitlines()
@@ -37,12 +39,26 @@
   lines = [len(l) > 3 and ":".join(l[3:]) or l for l in lines]
   return "\n".join(lines)
 
+
 def match_modulo_line_numbers(contents_a, contents_b):
   """File contents matcher that ignores line numbers."""
   contents_a = remove_debug_line_numbers(contents_a)
   contents_b = remove_debug_line_numbers(contents_b)
   return TestCommon.match_exact(contents_a, contents_b)
 
+
+@contextmanager
+def LocalEnv(local_env):
+  """Context manager to provide a local OS environment."""
+  old_env = os.environ.copy()
+  os.environ.update(local_env)
+  try:
+    yield
+  finally:
+    os.environ.clear()
+    os.environ.update(old_env)
+
+
 class TestGypBase(TestCommon.TestCommon):
   """
   Class for controlling end-to-end tests of gyp generators.
diff --git a/test/win/gyptest-link-safeseh.py b/test/win/gyptest-link-safeseh.py
new file mode 100644
index 0000000..0d84009
--- /dev/null
+++ b/test/win/gyptest-link-safeseh.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure safeseh setting is extracted properly.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'linker-flags'
+  test.run_gyp('safeseh.gyp', chdir=CHDIR)
+  test.build('safeseh.gyp', test.ALL, chdir=CHDIR)
+
+  def HasSafeExceptionHandlers(exe):
+    full_path = test.built_file_path(exe, chdir=CHDIR)
+    output = test.run_dumpbin('/LOADCONFIG', full_path)
+    return '    Safe Exception Handler Table' in output
+
+  # From MSDN: http://msdn.microsoft.com/en-us/library/9a89h429.aspx
+  #   If /SAFESEH is not specified, the linker will produce an image with a
+  #   table of safe exceptions handlers if all modules are compatible with
+  #   the safe exception handling feature. If any modules were not
+  #   compatible with safe exception handling feature, the resulting image
+  #   will not contain a table of safe exception handlers.
+  if HasSafeExceptionHandlers('test_safeseh_default.exe'):
+    test.fail_test()
+  if HasSafeExceptionHandlers('test_safeseh_no.exe'):
+    test.fail_test()
+  if not HasSafeExceptionHandlers('test_safeseh_yes.exe'):
+    test.fail_test()
+
+  test.pass_test()
diff --git a/test/win/gyptest-ml-safeseh.py b/test/win/gyptest-ml-safeseh.py
new file mode 100644
index 0000000..ec702b9
--- /dev/null
+++ b/test/win/gyptest-ml-safeseh.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Make sure the /safeseh option can be passed to ml.
+"""
+
+import TestGyp
+
+import sys
+
+if sys.platform == 'win32':
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  CHDIR = 'ml-safeseh'
+  test.run_gyp('ml-safeseh.gyp', chdir=CHDIR)
+  test.build('ml-safeseh.gyp', test.ALL, chdir=CHDIR)
+
+  test.pass_test()
diff --git a/test/win/linker-flags/safeseh.gyp b/test/win/linker-flags/safeseh.gyp
new file mode 100644
index 0000000..6103620
--- /dev/null
+++ b/test/win/linker-flags/safeseh.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'test_safeseh_default',
+      'type': 'executable',
+      'msvs_settings': {
+      },
+      'sources': [
+        'safeseh_hello.cc',
+        'safeseh_zero.asm',
+      ],
+    },
+    {
+      'target_name': 'test_safeseh_no',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'ImageHasSafeExceptionHandlers': 'false',
+        },
+      },
+      'sources': [
+        'safeseh_hello.cc',
+        'safeseh_zero.asm',
+      ],
+    },
+    {
+      'target_name': 'test_safeseh_yes',
+      'type': 'executable',
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'ImageHasSafeExceptionHandlers': 'true',
+        },
+        'MASM': {
+          'UseSafeExceptionHandlers': 'true',
+        },
+      },
+      'sources': [
+        'safeseh_hello.cc',
+        'safeseh_zero.asm',
+      ],
+    },
+  ]
+}
diff --git a/test/win/linker-flags/safeseh_hello.cc b/test/win/linker-flags/safeseh_hello.cc
new file mode 100644
index 0000000..6141300
--- /dev/null
+++ b/test/win/linker-flags/safeseh_hello.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern "C" {
+int zero(void);
+}
+
+int main() {
+  return zero();
+}
diff --git a/test/win/linker-flags/safeseh_zero.asm b/test/win/linker-flags/safeseh_zero.asm
new file mode 100644
index 0000000..62da0df
--- /dev/null
+++ b/test/win/linker-flags/safeseh_zero.asm
@@ -0,0 +1,10 @@
+.MODEL FLAT, C
+.CODE
+
+PUBLIC  zero
+zero    PROC
+        xor     eax, eax
+        ret     0
+zero    ENDP
+
+END
diff --git a/test/win/ml-safeseh/a.asm b/test/win/ml-safeseh/a.asm
new file mode 100644
index 0000000..62da0df
--- /dev/null
+++ b/test/win/ml-safeseh/a.asm
@@ -0,0 +1,10 @@
+.MODEL FLAT, C
+.CODE
+
+PUBLIC  zero
+zero    PROC
+        xor     eax, eax
+        ret     0
+zero    ENDP
+
+END
diff --git a/test/win/ml-safeseh/hello.cc b/test/win/ml-safeseh/hello.cc
new file mode 100644
index 0000000..6141300
--- /dev/null
+++ b/test/win/ml-safeseh/hello.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern "C" {
+int zero(void);
+}
+
+int main() {
+  return zero();
+}
diff --git a/test/win/ml-safeseh/ml-safeseh.gyp b/test/win/ml-safeseh/ml-safeseh.gyp
new file mode 100644
index 0000000..bf8618f
--- /dev/null
+++ b/test/win/ml-safeseh/ml-safeseh.gyp
@@ -0,0 +1,24 @@
+# Copyright (c) 2014 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+    {
+      'target_name': 'ml_safeseh',
+      'type': 'executable',
+      'sources': [
+        'hello.cc',
+        'a.asm',
+      ],
+      'msvs_settings': {
+        'VCLinkerTool': {
+          'ImageHasSafeExceptionHandlers': 'true',
+        },
+        'MASM': {
+          'UseSafeExceptionHandlers': 'true',
+        },
+      },
+    },
+  ]
+}