[PATCH v3 07/13] loader: Don't clobber existing memory mappings when reserving addresses.

Jinoh Kang jinoh.kang.kr at gmail.com
Wed Jan 26 10:50:45 CST 2022


On 1/26/22 18:06, Alexandre Julliard wrote:
> Jinoh Kang <jinoh.kang.kr at gmail.com> writes:
> 
>> On 1/26/22 00:48, Alexandre Julliard wrote:
>>> Jinoh Kang <jinoh.kang.kr at gmail.com> writes:
>>>
>>>> Today, the preloader makes no attempt to avoid unmapping existing
>>>> memory mappings except the initial stack.  This results in irrevocably
>>>> unmapping some useful preallocated memory areas, such as vDSO.
>>>>
>>>> Fix this by reading /proc/self/maps for existing VMAs, and splitting
>>>> mmap() calls to avoid erasing existing memory mappings.
>>>
>>> That defeats the purpose of using the preloader.
>>
>> The intention was to *incrementally* scrape memory areas for the reserved ranges,
>> relocating any critical areas (vDSO, stack, ...) along the way.
>>
>> It's also why this change is useless without the subsequent patches,
>> which calls map_reserve_preload_ranges again to actually fill out all
>> the gaps previously occupied by vDSO/stack.
> 
> I don't see the point. If you want to remap vDSO you can do that first,
> and then reserve the full range. You don't need all that complexity.

If we remap vDSO _without_ reserving memory first, then the kernel may
end up choosing a reserved address for the new vDSO address, especially
on 32-bit.

We can implement the address allocation algorithm from scratch avoiding
the preload area explicitly ourselves, but I suppose it would result in
even more complexity.  This is also why we reserve those ranges in the
first place -- to let OS pick the address for us.

> 
> And as general advice for your patches, please try to avoid changing
> things that don't need changing, or adding infrastructure that isn't
> needed. It will make it easier to see the actual changes.
> 

My apologies for complicating the review work.  I'll try to separate such
patches into another serie, or omit them entirely if there's really no need
for them.

Perhaps there was something that I was thinking wrong about along the way.
In that case, I'll try my best to explain my motivation and/or assumption behind
those patches.  I'd like to not repeat the same mistake again, so I'd be happy to
learn about what went wrong (so that I can correct it).  Please feel free to
ignore them if you wish, though.

- loader: Use long instead of int for syscall return type in i386 code.

  I was planning to add more syscalls, and found that i386 code used "int" for
  syscall returns. My assumption was that it was a style issue (presumably
  32-bit-area Wine's leftover) that I was expected to address _before_ I could
  add more inline asm blocks.

  [The reason why I found "int" confusing was that I usually read "long" as
   "machine register-width integer," and "int" as "integer that either only
   needs to hold small values (e.g. exit code) _or_ has to be 32-bit for some
   reason."  Granted int = long on ILP32, but someone looking at the
   code might not be able to immediately verify that the type is correct unless
   they also consider that "int $0x80" is for the i386 ABI (or that the code region
   is guarded by ifdef __i386__), and i386 is a 32-bit architecture.
   I supposed that would be extra cognitive load for someone reviewing/auditing
   the code.]

  Perhaps my mistake here was one of the following:
  1. The code style wasn't an issue at all. I (incorrectly) assumed that
     the code style was a general consensus among systems programmers.
  2. The code style was indeed a problem, but it wasn't really required to
     fix them in the *same* patch serie.
  3. The style fix was required, but it came too early in the serie.

- loader: Remove GCC <=4.x EBX register spilling workaround for i386.

  Similar to above, but debugging related.  Again I was adding asm blocks
  around, so I felt it obliged to fix it before adding more code.

- loader: Enable dumping additional vectors in dump_auxiliary.

  This is not a critical patch, but merely a debugging aid.  Since it was
  obvious from the subject, I supposed it wouldn't hurt to include it
  towards the end of the series.
  I agree it would certainly have been better off as a separate patch, however.


Meanwhile, following are patches that I deem necessary and not gratuitous:

- loader: Refactor argv/envp/auxv management.

  This was necessary because I had to pass around the pointers to
  stack objects a lot.  Examples include getenv() for letting
  user control remapping behaviour via env vars, and stack relocation
  (which requires shifting all the argv/envp/auxv pointers).
  If the pointer variables were not in one place, the latter would
  make the code a lot hairy (by passing around all the scattered
  stack pointers) and unmaintainable.

- loader: Refactor number parsing to own function.

  Number parsing was only for WINEPRELOADRESERVE.  Now I need it for
  parsing /proc/self/maps as well.


I also looked through all of my past patchsets, and here's my thoughts about them:

- kernel32/tests: Test module refcounting with forwarded exports.
  => You have pointed out that the IATGAS hack is ugly (which is true).
     Perhaps this one counts as an "unnecessary infrastructure."

     As for the justification of a new DLL (forward4), it was particularly
     hard to find a concrete example that exactly suits the tests' needs.

     1. The DLL has to forward calls to another DLL *but* must not actually
        import from it.  This excludes DLLs like kernel32 which both forwards to
        *and* imports from kernelbase.
     2. The above condition must hold for all Windows versions being tested *and*
        in Wine.
     3. The DLL must not have been already loaded (either directly or indirectly via
        dependencies) in the process.  This excludes DLLs like kernel32, advapi,
        user32, gdi32, shell32, setupapi, userenv, and etc.

     The most recent iteration of this patchset uses ICMP/IPHLPAPI, but I'm still
     not 100% sure about the compatibility issue.
     An alternative would be to keep forward4 and modify winebuild so that TESTDLLs
     can import from other TESTDLLs, but it seemed like an overkill.

- winedbg(gdbproxy): don't misbehave on module names w/ special characters; modernise
  => Patchset does contain a lot of refactoring work, but I tried to justify them
     in the commit message body to my best.

- sock_recv() fix series
  => I attempted to minimize extra changes and/or infrastructure, but it might not have been perfect.
     In case some non-obvious change was needed, I tried to justify them in the patch message body.
     Perhaps there are other ways to implement them I couldn't think of.

Meanwhile following patches are ostensibly gratuitous in nature (it might or might not be useful; it's up to your decision):

- winedbg: use heap allocation for module filenames in handle_debug_event.
  => May seem gratuitous, but fixes module filenames being truncated over MAX_PATH.
- server: Allow skipping debug handle retrieval in get_process_debug_info.
  => Functionality may be gratuitous, but may closely match Windows NT kernel more.
     Practially untestable (Wine lacks needed infrastructure) for now, so up to the maintainer's decision.
- ntdll: Implement NtSetInformationVirtualMemory.
  => Functionality may be gratuitous or maybe some apps need it, up to the maintainer's decision.
- ntdll: Implement __fastfail().
  => Functionality may be gratuitous or maybe some apps need it, up to the maintainer's decision.
- ntdll: Make syscall dispatcher properly restore X16 and X17 in ARM64.
  => Completely up to the maintainer's decision.
- ws2_32/tests: Add order-agnostic check in test_simultaneous_async_recv.
  => Completely up to the maintainer's decision.

Again, thanks a lot!

-- 
Sincerely,
Jinoh Kang



More information about the wine-devel mailing list