[PATCH] vcruntime140_1: Support two continuation addresses for catchblock.

Paul Gofman pgofman at codeweavers.com
Tue Mar 2 13:30:04 CST 2021


I am attaching the MSVC test case based on Piotr's finding how to
reproduce the case from MSVC (there is a source and the .exe compiled
with cl.exe 19.28.29336 for x64).

On 3/2/21 22:26, Paul Gofman wrote:
> MSVC generates that sometimes when there is a goto from catch block.
>
> Fixes a crash in Company of Heroes 2.
>
> Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
> ---
>  dlls/vcruntime140_1/except_x86_64.c | 48 +++++++++++++++++++++++------
>  1 file changed, 38 insertions(+), 10 deletions(-)
>
> diff --git a/dlls/vcruntime140_1/except_x86_64.c b/dlls/vcruntime140_1/except_x86_64.c
> index a5a760b7b08..37c087469d0 100644
> --- a/dlls/vcruntime140_1/except_x86_64.c
> +++ b/dlls/vcruntime140_1/except_x86_64.c
> @@ -66,12 +66,14 @@ typedef struct
>      UINT type_info;
>      int offset;
>      UINT handler;
> -    UINT ret_addr;
> +    UINT ret_addr[2];
>  } catchblock_info;
>  #define CATCHBLOCK_FLAGS     0x01
>  #define CATCHBLOCK_TYPE_INFO 0x02
>  #define CATCHBLOCK_OFFSET    0x04
> -#define CATCHBLOCK_RET_ADDR  0x10
> +#define CATCHBLOCK_RET_ADDR_MASK 0x30
> +#define CATCHBLOCK_RET_ADDR      0x10
> +#define CATCHBLOCK_TWO_RET_ADDRS 0x20
>  
>  #define TYPE_FLAG_CONST      1
>  #define TYPE_FLAG_VOLATILE   2
> @@ -214,19 +216,31 @@ static void read_tryblock_info(BYTE **b, tryblock_info *ti, ULONG64 image_base)
>  
>  static BOOL read_catchblock_info(BYTE **b, catchblock_info *ci)
>  {
> +    BYTE ret_addr_type;
>      memset(ci, 0, sizeof(*ci));
>      ci->header = **b;
>      (*b)++;
> -    if (ci->header & ~(CATCHBLOCK_FLAGS | CATCHBLOCK_TYPE_INFO | CATCHBLOCK_OFFSET | CATCHBLOCK_RET_ADDR))
> +    if (ci->header & ~(CATCHBLOCK_FLAGS | CATCHBLOCK_TYPE_INFO | CATCHBLOCK_OFFSET | CATCHBLOCK_RET_ADDR_MASK))
>      {
>          FIXME("unknown header: %x\n", ci->header);
>          return FALSE;
>      }
> +    ret_addr_type = ci->header & CATCHBLOCK_RET_ADDR_MASK;
> +    if (ret_addr_type && ret_addr_type != CATCHBLOCK_RET_ADDR && ret_addr_type != CATCHBLOCK_TWO_RET_ADDRS)
> +    {
> +        FIXME("unsupported ret addr type %#x.\n", ret_addr_type);
> +        return FALSE;
> +    }
> +
>      if (ci->header & CATCHBLOCK_FLAGS) ci->flags = decode_uint(b);
>      if (ci->header & CATCHBLOCK_TYPE_INFO) ci->type_info = read_rva(b);
>      if (ci->header & CATCHBLOCK_OFFSET) ci->offset = decode_uint(b);
>      ci->handler = read_rva(b);
> -    if (ci->header & CATCHBLOCK_RET_ADDR) ci->ret_addr = decode_uint(b);
> +    if (ret_addr_type == CATCHBLOCK_RET_ADDR || ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
> +        ci->ret_addr[0] = decode_uint(b);
> +    if (ret_addr_type == CATCHBLOCK_TWO_RET_ADDRS)
> +        ci->ret_addr[1] = decode_uint(b);
> +
>      return TRUE;
>  }
>  
> @@ -303,9 +317,9 @@ static BOOL validate_cxx_function_descr4(const cxx_function_descr *descr, DISPAT
>              catchblock_info ci;
>              if (!read_catchblock_info(&catchblock, &ci)) return FALSE;
>              TRACE("        %d: header 0x%x offset %d handler 0x%x(%p) "
> -                    "ret addr %x type %x %s\n", j, ci.header, ci.offset,
> +                    "ret addr[0] %#x ret_addr[1] %#x type %#x %s\n", j, ci.header, ci.offset,
>                      ci.handler, rva_to_ptr(ci.handler, image_base),
> -                    ci.ret_addr, ci.type_info,
> +                    ci.ret_addr[0], ci.ret_addr[1], ci.type_info,
>                      dbgstr_type_info(rva_to_ptr(ci.type_info, image_base)));
>          }
>      }
> @@ -535,8 +549,19 @@ static void* WINAPI call_catch_block4(EXCEPTION_RECORD *rec)
>      __FINALLY_CTX(cxx_catch_cleanup, &ctx)
>  
>      FlsSetValue(fls_index, (void*)-2);
> -    if (rec->ExceptionInformation[8]) return (void*)rec->ExceptionInformation[8];
> -    return ret_addr;
> +    TRACE("handler returned %p, ret_addr[0] %p, ret_addr[1] %p.\n",
> +            ret_addr, rec->ExceptionInformation[8], rec->ExceptionInformation[9]);
> +
> +    if (rec->ExceptionInformation[9])
> +    {
> +        if ((ULONG_PTR)ret_addr > 1)
> +        {
> +            FIXME("unexpected handler result %p.\n", ret_addr);
> +            return rec->ExceptionInformation[8] ? (void *)rec->ExceptionInformation[8] : ret_addr;
> +        }
> +        return (void*)rec->ExceptionInformation[8 + (ULONG_PTR)ret_addr];
> +    }
> +    return rec->ExceptionInformation[8] ? (void *)rec->ExceptionInformation[8] : ret_addr;
>  }
>  
>  static inline BOOL cxx_is_consolidate(const EXCEPTION_RECORD *rec)
> @@ -620,9 +645,12 @@ static inline void find_catch_block4(EXCEPTION_RECORD *rec, CONTEXT *context,
>                  (ULONG_PTR)rva_to_ptr(ci.handler, dispatch->ImageBase);
>              catch_record.ExceptionInformation[6] = (ULONG_PTR)untrans_rec;
>              catch_record.ExceptionInformation[7] = (ULONG_PTR)context;
> -            if (ci.ret_addr)
> +            if (ci.ret_addr[0])
>                  catch_record.ExceptionInformation[8] = (ULONG_PTR)rva_to_ptr(
> -                    ci.ret_addr + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase);
> +                    ci.ret_addr[0] + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase);
> +            if (ci.ret_addr[1])
> +                catch_record.ExceptionInformation[9] = (ULONG_PTR)rva_to_ptr(
> +                    ci.ret_addr[1] + dispatch->FunctionEntry->BeginAddress, dispatch->ImageBase);
>              RtlUnwindEx((void*)frame, (void*)dispatch->ControlPc, &catch_record, NULL, &ctx, NULL);
>          }
>      }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.tgz
Type: application/x-compressed-tar
Size: 4502 bytes
Desc: not available
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20210302/fbb092cc/attachment-0001.bin>


More information about the wine-devel mailing list