-
Hello. This was reported on one of my projects here: Tyrrrz/DiscordChatExporter#1016 Judging by the stack trace, the exception appears to be thrown by one of the compiled regular expressions: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at DynamicClass.Regex22_Scan(System.Text.RegularExpressions.RegexRunner, System.ReadOnlySpan`1<Char>)
qemu: uncaught target signal 6 (Aborted) - core dumped For reference, this is how the regexes are used, although nothing is particularly special about them. They're all created with the And here's the Dockerfile: The image runs perfectly fine on Windows, Linux, and non-ARM-based macOS. Unfortunately, I don't have the means to test it firsthand, but it seems that the users in the comments to that issue can reproduce the error very consistently on M1 Macs. Can you suggest what could be the issue and how can I go about resolving it? Thank you |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
Also experiencing this, but it was working for me back in January 2023. Both docker and the image (amd64 only) have had updates since then. My error is slightly different:
|
Beta Was this translation helpful? Give feedback.
-
I'll self-answer this and close the discussion because I found the solution. Below is a short overview of what you need to do to correctly build a Docker image for your .NET app, to seamlessly work on both x64 and arm64. In essence, Docker uses QEMU to emulate arm64 images on x64 (and vice versa). Dotnet does not support being emulated through QEMU, which is why you may get The simplest way to do that is by using Docker Buildx which is a set of extensions for Here's how the build process looks, taken from my GitHub Actions workflow file: name: docker
on: push
jobs:
deploy-latest:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
run: >
echo ${{ secrets.DOCKER_TOKEN }} |
docker login --username tyrrrz --password-stdin
- name: Build & push image
run: >
docker buildx build
--file DiscordChatExporter.Cli.dockerfile
--platform linux/amd64,linux/arm64
--push
--tag tyrrrz/discordchatexporter:latest
. The important part here is the The The # -- Build
# Specify the platform here so that we pull the SDK image matching the host platform,
# instead of the target platform specified during build by the `--platform` option.
# Use the .NET 8.0 preview because the `--arch` option is only available in that version.
# https://github.com/dotnet/dotnet-docker/issues/4388#issuecomment-1459038566
# TODO: switch images to Alpine once .NET 8.0 is released.
# Currently, the correct preview version is only available on Debian.
# https://github.com/dotnet/dotnet-docker/blob/main/samples/selecting-tags.md
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-preview AS build
# Expose the target architecture set by the `docker build --platform` option, so that
# we can build the assembly for the correct platform.
ARG TARGETARCH
WORKDIR /build
COPY favicon.ico .
COPY NuGet.config .
COPY Directory.Build.props .
COPY DiscordChatExporter.Core DiscordChatExporter.Core
COPY DiscordChatExporter.Cli DiscordChatExporter.Cli
# Publish a self-contained assembly so we can use a slimmer runtime image
RUN dotnet publish DiscordChatExporter.Cli \
--configuration Release \
--self-contained \
--use-current-runtime \
--arch $TARGETARCH \
--output publish/
# -- Run
# Use `runtime-deps` instead of `runtime` because we have a self-contained assembly
FROM --platform=$TARGETPLATFORM mcr.microsoft.com/dotnet/runtime-deps:7.0 AS run
COPY --from=build /build/publish /opt/dce
ENTRYPOINT ["/opt/dce/DiscordChatExporter.Cli"] The critical part here is the For The I am also building my assembly as self-contained to get a smaller runtime image size, but this is not required. Finally, the runtime stage of the image should remain pretty much unchanged. I added Once you put everything in place and push your images to the registry, this is how it should look: Now, when the user pulls your image, Docker will resolve the correct instance based on the host platform. This allows the underlying .NET app to run natively and without emulation. |
Beta Was this translation helpful? Give feedback.
I'll self-answer this and close the discussion because I found the solution. Below is a short overview of what you need to do to correctly build a Docker image for your .NET app, to seamlessly work on both x64 and arm64.
In essence, Docker uses QEMU to emulate arm64 images on x64 (and vice versa). Dotnet does not support being emulated through QEMU, which is why you may get
AccessViolatedException
s. The only solution is to provide an image that doesn't require emulation -- i.e. one matching the host platform. You can push multiple Docker images for different platforms under the same tag using a process called multi-arch build.The simplest way to do that is by using Docker Buildx which is…