Code Troubleshooting

Recode has been designed to just work. The aim is to be as compatible as possible without modification to the code but of course there are limitations. While Recode compatibility is improving all the time, C++ is an extremely complex language with various corner cases or platform specific extensions that can be hard to support reliably.

Code preparation will hopefully be straightforward. But if you run into problems this guide is here to help deal with any issues should they arise.

Tip

Before integrating Recode into a code-base for the first time, we recommended that you familiarize yourself with the problem code patterns described below.

Missing PCH include

MSVC treats PCH #include directives as markers for when to load the PCH data. However when using a PCH file the compiler /Yu option will not check to see if it can actually locate the included file. When Recode builds patch files it can’t reuse the PCH data and so it must be able to locate the correct PCH include in order to compile a patch.

If Recode cannot find the /Yu specified PCH header, the following error is issued:

SubDir\in_subdir.cpp : error recode: PCH header C:\path\to\expected\stdafx.h not found on any include search path
  Please ensure that C:\path\to\expected\stdafx.h can be found on the include search path, this is required for successful Recoding

If a PCH header has been found but it’s not the one that the PCH was compiled with, you will see this error:

SubDir\in_subdir.cpp : error recode: Incorrect PCH header stdafx.h included from 'C:\some\incorrect\path' expected header is: C:\path\to\expected\stdafx.h
  Please ensure that C:\path\to\expected\stdafx.h can be found before any others, this is required for successful Recoding

In both cases, ensure that you add the directory containing the PCH include file as the first include directory for the project.

Static local variables

Static local variables are static variables declared within a function:

void HasStaticLocals()
{
    static int s_declaredInFoo = 42;
    Bar(++s_declaredInFoo);
}

In most cases Recode can preserve the values of static local variables after patching, although it’s recommended that you avoid them where possible to avoid issues.

Tip

The easiest way to avoid issues is to move the static local variable declarations out of the functions and make them normal global variables where possible.

Warning

VS2015+ compilers do not record information for static local variables within static functions or functions within anonymous namespaces (ie. all functions without public linkage) with compiler optimizations active. This may prevent Recode from preserving such variables between Recodes. Make any such functions non-static (public linkage) to avoid this issue or move the variable outside of the function.

Thread local variables

Thread local storage (TLS) variables used to track values specific to each thread. Variables are declared as thread local using the storage-class modifier: __declspec(thread)

Recode can support TLS variables in most cases but where possible avoid placing TLS variables in header files to reduce the chance of problems during Recode patching.

Warning

Static local TLS variables are not supported. Recode will fail if any functions contain variables declared with static __declspec(thread) storage.

Important

Recode does not support adding (or renaming) TLS variables at runtime.

Function local extern variables

Function local extern variables are global variables declared within function scope:

int get_foo()
{
    extern int g_foo;
}

Recode can handle most function local extern variables. However, any declared in templated functions may cause issues and should be avoided where possible.

To workaround any issues, simply move the declaration out of the function body.

Forward declaration of type using DLL import/export

If you encounter a C4273 warning in conjunction with a C2491 error during a Recode:

foo.h(123) : warning C4273: 'ms_instance' : inconsistent dll linkage
    foo.h(12) : see previous definition of 'protected: static Foo * & Foo::ms_instance'
foo.h(173) : error C2491: 'Foo::ms_instance' : definition of dllimport static data member not allowed

You may have forward declared a type with __declspec(dllimport). For instance:

// Declare the DLL_API import/export macro
#ifdef DLL_EXPORTS
    #define DLL_API __declspec(dllexport)
#else
    #define DLL_API __declspec(dllimport)
#endif

// Forward declare the Foo class
// This unnecessary DLL_API can cause C4273 during Recoding
class DLL_API Foo;

// Define the Foo class
class DLL_API Foo
{
    // ...
};

Since there is no need to forward declare types as dllimport/dllexport you can safely remove the __declspec([...]) (or DLL_API in this example) from the forward declaration.

Anonymous enums

Anonymous enums may cause problems if they are used as template parameters. This can cause issues linking both functions and data. To avoid problems at runtime Recode will raise a warning if it detects such usage:

enum.cpp(48): recode warning : anonymous enums cannot be used as template arguments for classes with static members. Resolve by naming the enum.
enum.cpp(69): recode note : anonymous enum used to instantiate a template class here.

Ensure any enum used as a template parameter is named to allow Recode work reliably.

Reference template parameters

Recode does not support using global variables references as template parameters:

template <int& REF>
struct UsesRef
{
    int& get_val() { return REF; }
};

int g_val = 42;
UsesRef<g_val> g_willFailToRecode;

An easy workaround is to use a pointer template parameter instead:

template <int* PTR>
struct UsesRef
{
    int& get_val() { return *PTR; }
};

int g_val = 42;
UsesRef<&g_val> g_safeToRecode;