diff options
author | enal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-28 02:02:21 +0000 |
---|---|---|
committer | enal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-28 02:02:21 +0000 |
commit | cde840d31743fe685066c92060a7e045516b9a84 (patch) | |
tree | 6465a2348833c3591ead4f39426834c68e69ebb7 /media/base/media_win.cc | |
parent | 09dd320b7078a141e312c0bcf7297c431ed6469f (diff) | |
download | chromium_src-cde840d31743fe685066c92060a7e045516b9a84.zip chromium_src-cde840d31743fe685066c92060a7e045516b9a84.tar.gz chromium_src-cde840d31743fe685066c92060a7e045516b9a84.tar.bz2 |
Workaround for Windows-only crash inside delay load helper.
Crash report shows access violation inside LoadLibraryExA() called from
DelayLoadHelper2(), and we cannot figure out what exactly causes the problem.
In theory it can be caused by Chrome terminating while we are initializing ffmpeg
code, but I am not sure.
Workaround is to call delay load helper to patch import tables during renderer
initialization. We are loading ffmpeg DLL at this moment anyways but do not patch
import tables. Extra overhead is negligeable compared to disk access time.
Also fixed potential problem -- LoadLibraryEx() does not accept relative paths when
used as we are using it. During normal startup we are getting absolute path, but
customer can specify relative path as a command-line flag. Fix is to call Windows API
GetFullPathName() to get rid of relative path.
BUG=110983.
Review URL: http://codereview.chromium.org/9450001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123865 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/base/media_win.cc')
-rw-r--r-- | media/base/media_win.cc | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/media/base/media_win.cc b/media/base/media_win.cc index 9462c02..6b4c07e 100644 --- a/media/base/media_win.cc +++ b/media/base/media_win.cc @@ -1,10 +1,11 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media/base/media.h" #include <windows.h> +#include <delayimp.h> #include "base/file_path.h" #include "base/logging.h" @@ -12,6 +13,8 @@ #include "base/native_library.h" #include "base/path_service.h" +#pragma comment(lib, "delayimp.lib") + namespace media { enum FFmpegDLLKeys { @@ -21,18 +24,18 @@ enum FFmpegDLLKeys { }; // Retrieves the DLLName for the given key. -static FilePath::CharType* GetDLLName(FFmpegDLLKeys dll_key) { +static const char* GetDLLName(FFmpegDLLKeys dll_key) { // TODO(ajwong): Do we want to lock to a specific ffmpeg version? switch (dll_key) { case FILE_LIBAVCODEC: - return FILE_PATH_LITERAL("avcodec-53.dll"); + return "avcodec-53.dll"; case FILE_LIBAVFORMAT: - return FILE_PATH_LITERAL("avformat-53.dll"); + return "avformat-53.dll"; case FILE_LIBAVUTIL: - return FILE_PATH_LITERAL("avutil-51.dll"); + return "avutil-51.dll"; default: LOG(DFATAL) << "Invalid DLL key requested: " << dll_key; - return FILE_PATH_LITERAL(""); + return ""; } } @@ -44,6 +47,11 @@ bool InitializeMediaLibrary(const FilePath& base_path) { if (g_media_library_is_initialized) return true; + // LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH) cannot handle + // relative path. + if (!base_path.IsAbsolute()) + return false; + FFmpegDLLKeys path_keys[] = { media::FILE_LIBAVCODEC, media::FILE_LIBAVFORMAT, @@ -52,12 +60,12 @@ bool InitializeMediaLibrary(const FilePath& base_path) { HMODULE libs[arraysize(path_keys)] = {NULL}; for (size_t i = 0; i < arraysize(path_keys); ++i) { - FilePath path = base_path.Append(GetDLLName(path_keys[i])); + FilePath path = base_path.AppendASCII(GetDLLName(path_keys[i])); // Use alternate DLL search path so we don't load dependencies from the // system path. Refer to http://crbug.com/35857 const wchar_t* cpath = path.value().c_str(); - libs[i] = LoadLibraryEx(cpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + libs[i] = ::LoadLibraryEx(cpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); if (!libs[i]) break; } @@ -65,17 +73,41 @@ bool InitializeMediaLibrary(const FilePath& base_path) { // Check that we loaded all libraries successfully. We only need to check the // last array element because the loop above will break without initializing // it on any prior error. - g_media_library_is_initialized = (libs[arraysize(libs) - 1] != NULL); + bool media_library_is_initialized = (libs[arraysize(libs) - 1] != NULL); - if (!g_media_library_is_initialized) { + if (!media_library_is_initialized) { // Free any loaded libraries if we weren't successful. for (size_t i = 0; i < arraysize(libs) && libs[i] != NULL; ++i) { FreeLibrary(libs[i]); libs[i] = NULL; // Just to be safe. } + return false; } - return g_media_library_is_initialized; + // Workaround for http://crbug.com/110983 + // LoadLibrary() sometimes AV's when called by delay load helper when we + // call function in ffmpeg for the first time, and we don't know why. + // Force delay load helper to fix import table here instead. + // Theoretically, there is no need to call LoadLibrary() before + // __HrLoadAllImportsForDll(), it will call LoadLibrary() itself, but there + // is no way to specify LOAD_WITH_ALTERED_SEARCH_PATH when calling + // __HrLoadAllImportsForDll(). So we do everything in 2 steps -- first call + // LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH), then call + // __HrLoadAllImportsForDll(). Overhead is negligible compared to disk + // access time. + // Note: in case of error we are not unloading DLL because unload requires + // extra resources and should not be necessary; if we ever decide to + // unload by calling __FUnloadDelayLoadedDLL() please add /DELAY:UNLOAD + // to the linker command line. + // TODO(enal): remove that code when we find underlying issue. Delay load + // should work if library is alreday in memory, regardless of permissions... + for (size_t i = 0; i < arraysize(path_keys); ++i) { + if (FAILED(::__HrLoadAllImportsForDll(GetDLLName(path_keys[i])))) + media_library_is_initialized = false; + } + + g_media_library_is_initialized = media_library_is_initialized; + return media_library_is_initialized; } void InitializeMediaLibraryForTesting() { |