mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-07-08 11:29:58 +02:00
## Summary of the Pull Request The File Locksmith IPC layer reads and writes raw UTF-16 (WCHAR) bytes to `last-run.log`, but all three stream opens were using the default text mode. On Windows, the CRT translates `0x0A` bytes to `0x0D 0x0A` on write and collapses `0x0D 0x0A` back to `0x0A` on read. Because each WCHAR is 2 bytes, any code unit whose little-endian byte pair contains `0x0A` in the low position (e.g. `U+010A`, `U+0A0D`) is silently corrupted. The fix opens all three streams in binary mode and adds an explicit open-failure guard. ```cpp // IPC.cpp — Writer::start() // Before m_stream = std::ofstream(path); // After m_stream = std::ofstream(path, std::ios::binary); // + is_open() guard returning E_FAIL on failure // NativeMethods.cpp — StartAsElevated() writer // Before std::ofstream stream(paths_file()); // After std::ofstream stream(paths_file(), std::ios::binary); // NativeMethods.cpp — ReadPathsFromFile() reader // Before std::ifstream stream(paths_file()); // After std::ifstream stream(paths_file(), std::ios::binary); ``` ## PR Checklist - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx ## Detailed Description of the Pull Request / Additional comments Three targeted changes across two files: 1. **`FileLocksmithLib/IPC.cpp` — `Writer::start()`**: switched `std::ofstream` from text to binary mode and added an `is_open()` check that returns `E_FAIL` immediately when the file cannot be opened (previously the try/catch did not catch a silent open failure because `std::ofstream` does not throw by default). 2. **`FileLocksmithLibInterop/NativeMethods.cpp` — `StartAsElevated()`**: switched `std::ofstream` from text to binary mode. This is the elevated-restart writer path; without this fix, Unicode corruption persisted when File Locksmith relaunched as administrator. 3. **`FileLocksmithLibInterop/NativeMethods.cpp` — `ReadPathsFromFile()`**: switched `std::ifstream` from text to binary mode. This is the symmetric reader-side bug — even with both writers corrected, the CRT text-mode reader could collapse a `0x0D 0x0A` byte pair (a valid UTF-16 LE code unit, e.g. U+0A0D GURMUKHI EK ONKAR) into a single byte, desynchronising the 2-bytes-at-a-time read loop and corrupting all subsequent path data. No behaviour change for purely ASCII paths. Paths containing Unicode code points whose little-endian UTF-16 byte pair spans `0x0D 0x0A` were silently corrupted in all three code paths before this fix. ## Validation Steps Performed - Code review: no issues flagged. - Full diff reviewed: all three stream opens (`ofstream` writer in `IPC.cpp`, `ofstream` writer in `NativeMethods.cpp`, `ifstream` reader in `NativeMethods.cpp`) now use `std::ios::binary`, making write and read paths byte-exact and symmetric. - Mechanically correct: `std::ios::binary` suppresses Windows CRT `\n`↔`\r\n` translation; the delimiter `L'\n'` (LE bytes `0x0A 0x00`) is unambiguous in binary mode and is handled correctly by the existing read loop. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com> Co-authored-by: Muyuan Li (from Dev Box) <muyuanli@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
68 lines
1.3 KiB
C++
68 lines
1.3 KiB
C++
#include "pch.h"
|
|
|
|
#include "IPC.h"
|
|
#include "Constants.h"
|
|
|
|
#include <common/SettingsAPI/settings_helpers.h>
|
|
|
|
constexpr DWORD DefaultPipeBufferSize = 8192;
|
|
constexpr DWORD DefaultPipeTimeoutMillis = 200;
|
|
|
|
namespace ipc
|
|
{
|
|
Writer::Writer()
|
|
{
|
|
start();
|
|
}
|
|
|
|
Writer::~Writer()
|
|
{
|
|
finish();
|
|
}
|
|
|
|
HRESULT Writer::start()
|
|
{
|
|
std::wstring path = PTSettingsHelper::get_module_save_folder_location(constants::nonlocalizable::PowerToyName);
|
|
path += L"\\";
|
|
path += constants::nonlocalizable::LastRunPath;
|
|
|
|
try
|
|
{
|
|
m_stream = std::ofstream(path, std::ios::binary);
|
|
if (!m_stream.is_open())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
catch (...)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
HRESULT Writer::add_path(LPCWSTR path)
|
|
{
|
|
int length = lstrlenW(path);
|
|
if (!m_stream.write(reinterpret_cast<const char*>(path), length * sizeof(WCHAR)))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
WCHAR line_break = L'\n';
|
|
if (!m_stream.write(reinterpret_cast<const char*>(&line_break), sizeof(WCHAR)))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void Writer::finish()
|
|
{
|
|
add_path(L"");
|
|
m_stream.close();
|
|
}
|
|
}
|