This article describes the changes made in OWLNext 6.40 and later to support the 64-bit build mode.
OWLNext 6.32 introduced preliminary support for 64-bit. This consisted mainly of changes to some 32-bit API calls, and an overhaul of the thunking mechanism for message dispatch. OWLNext 6.34 included further fixes to the dispatch framework. However, the 64-bit build mode for these early versions is not officially supported and should not be used in production code.
The following changes have been implemented for 64-bit support in OWLNext.
This change was implemented in [r759] and shipped in OWLNext 6.32. It involved a complete overhaul of the thunk generation code, since the 64-bit Microsoft compiler no longer supports in-line assembly code. The new implementation creates a thunk by linking a chunk of raw machine code with the window pointer and the address of the dispatch function. This run-time linking is done using a C++ template, which is instantiated for the relevant compiler and build mode. As before the thunk is allocated on an executable memory heap, as to support the Data Execution Prevention safety feature in Windows XP and later.
For more information about thunking in OWLNext, read Windows Message Dispatch in OWLNext, and for the gory details, see the source code (source/owlcore/owl.cpp (sourceforge.net)).
To support 64-bit, incompatible 32-bit types and calls had to be replaced by agnostic versions that map to the correct implementation depending on the build mode. This involved the replacement of functions such as SetWindowLong by the agnostic version SetWindowLongPtr. The latter function maps to the former in 32-bit build mode. See forum topic "64-bit Version" for details.
Here is a list of changes made:
int64 and uint64 in "include/owl/objstrm.h" [r1011]. uint32 to INT_PTR to allow pointers to objects to be safely stored [r1894].long to TParam2 [r2598].Also see the bug tracker for 64-bit issues.
The Windows API widely uses handles; internal object references (indices) that are cast to pointers, and hence look like regular pointers. While these pointers are 64-bit in x64 build mode, handles only use the lower 32 bits, i.e. the upper 32 bits are insignificant. The MSDN documentation states:
64-bit versions of Windows use 32-bit handles for interoperability. When sharing a handle between 32-bit and 64-bit applications, only the lower 32 bits are significant, so it is safe to truncate the handle (when passing it from 64-bit to 32-bit) or sign-extend the handle (when passing it from 32-bit to 64-bit).
See Programming Guide for 64-bit Windows.
While this means that the handle truncation issues identified above do not matter in practice, fixing them provides C++ type-safety and eliminates suspect code and the related warnings.
Message dispatch involves the encoding and decoding of message arguments. For 64-bit compatibility all of the message passing code needed to be reviewed and corrected.
Version 6.40 introduces a thoroughly overhauled dispatch framework [r1803] [r1804] [r1805] [r1810] [r1811] [r1823] [r1824]. This overhaul improves 64-bit support and simplifies review, testing and maintenance. The old Borland solution was not C++ conformant and was difficult to review and test for correctness. For more information about the old machinery, its issues and its new replacement, see Windows Message Dispatch in OWLNext.
Message passing code across all of OWLNext does manual encoding of the message arguments. All of these individual cases have been identified and reviewed for 64-bit correctness. No issues were found (see forum post "64-bit Version").
Proper handling of quantities, such as indices and sizes, that are larger than INT_MAX (~2 GB), is important for robust 64-bit applications. For example, 64-bit quantities arise for memory allocations, standard strings (owl::tstring) and containers (e.g. std::vector), and for file sizes and positions.
The policy adopted for OWLNext 6.40 is to not support 64-bit quantities unless explicitly documented for each function and class. The use of a 64-bit quantity will in general cause undefined behaviour (UB).
This means that, in general, the client code is responsible for detecting and handling 64-bit quantities before calling OWLNext code, e.g. by reporting errors. For example, the client code should check strings for 64-bit size and handle it appropriately, e.g. throw an exception, before passing a string to OWLNext.
void SetText(TEdit& c, const tstring& t)
{
if (t.size() > INT_MAX) throw runtime_error("Too much text for OWLNext");
c.SetText(t);
}
Bugs: #237
Commit: [r1010]
Commit: [r1011]
Commit: [r1026]
Commit: [r1242]
Commit: [r1260]
Commit: [r1709]
Commit: [r1714]
Commit: [r1793]
Commit: [r1800]
Commit: [r1803]
Commit: [r1804]
Commit: [r1805]
Commit: [r1810]
Commit: [r1811]
Commit: [r1823]
Commit: [r1824]
Commit: [r1894]
Commit: [r2598]
Commit: [r756]
Commit: [r757]
Commit: [r759]
Commit: [r764]
Commit: [r765]
Commit: [r767]
Commit: [r770]
Commit: [r771]
Commit: [r775]
Commit: [r781]
Commit: [r789]
Commit: [r792]
Commit: [r799]
Commit: [r804]
Commit: [r806]
Commit: [r807]
Commit: [r823]
Commit: [r846]
Commit: [r852]
Commit: [r854]
Commit: [r865]
Commit: [r868]
Commit: [r880]
Commit: [r888]
Discussion: Own Compare function for SortChildren of TTreeViewCtrl
Discussion: Porting from 6.36 to 6.44 (some help needed)
Discussion: OWLNext 6.40.5 and 6.34.3 Updates
Discussion: 64-bit OWLNext has arrived!
Discussion: Help on incompatible changes in 7 series
News: 2014/04/64-bit-owlnext-640-prerelease
News: 2016/07/owlnext-usage-survey-32-bit-vs-64-bit
News: 2019/09/state-of-owlnext--10-years-since-630
Wiki: Frequently_Asked_Questions
Wiki: History
Wiki: Knowledge_Base
Wiki: Upgrading_from_OWL
Wiki: Vidar_Hasfjord
Wiki: Windows_Message_Dispatch_in_OWLNext
Proper handling of 64-bit sizes
Proper handling of 64-bit sizes is important for robust 64-bit support. For example, 64-bit sizes arise for memory allocations, standard strings (owl::tstring) and containers (e.g. std::vector), and for file sizes and positions. We have the following options for the handling of 64-bit sizes, sorted by increasing robustness.
For example, many Windows API functions that deal with text, only support a 32-bit size. However, OWLNext uses owl::tstring (and raw arrays) that have 64-bit size. If we ignore this issue, i.e. option (1), sizes will be truncated and cause undefined behaviour, e.g. crashes. Note that truncating a size is not the same as truncating a text. Truncating a 64-bit value gives an arbitrary value in the 32-bit range. This makes option (1) brittle with potentially unexpected results. Option (2), clamping the size to the 32-bit range, has the drawback that it truncates the text. Text truncation is rarely insignificant. Option (3) is unsatisfactory, since the text size is most often determined at run-time, so the issue can not be eliminated in debug builds (asserts should only be used to test programming logic errors). That leaves option (4) as the most robust solution for text.
A similar analysis can be applied to containers and files.
Due to the current state of the OWLNext project, the simplest solution is to adopt option (1), i.e. declare that using 64-bit sizes with OWLNext causes undefined behaviour (UB), unless 64-bit support (or behaviour) is explicitly documented for each function and class. In the long term, option (4) would be desirable.