https://github.com/aseprite/laf/pull/84
From: "Azamat H. Hackimov" <azamat.hackimov@gmail.com>
Date: Sun, 14 Apr 2024 21:47:02 +0300
Subject: [PATCH] Fix strict-alias warnings

reinterpret_cast on pointers break strict-aliasing rule (-Wstrict-aliasing). Implemented internal function copy_reinterpret_cast that memcpy pointer into type, that can be converted to desired type.
--- a/laf/base/cfile.cpp
+++ b/laf/base/cfile.cpp
@@ -7,6 +7,7 @@
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
+#include "base/mem_utils.h"
 
 #include <cstdio>
 
@@ -114,7 +115,7 @@ float fgetf(FILE* file)
 
   // Little endian.
   int v = ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
-  return *reinterpret_cast<float*>(&v);
+  return *copy_reinterpret_cast<float*>(&v);
 }
 
 // Reads a 64-bit double-precision floating point number using
@@ -156,7 +157,7 @@ double fgetd(FILE* file)
                  ((long long)b3 << 16) |
                  ((long long)b2 << 8) |
                  (long long)b1);
-  return *reinterpret_cast<double*>(&v);
+  return *copy_reinterpret_cast<double*>(&v);
 }
 
 // Writes a word using little-endian byte ordering.
@@ -231,7 +232,7 @@ int fputq(long long l, FILE* file)
 // Returns 0 in success or -1 in error
 int fputf(float l, FILE* file)
 {
-  int b = *(reinterpret_cast<int*>(&l));
+  int b = *(copy_reinterpret_cast<int*>(&l));
   int b1, b2, b3, b4;
 
   // Little endian.
@@ -254,7 +255,7 @@ int fputf(float l, FILE* file)
 // Returns 0 in success or -1 in error
 int fputd(double l, FILE* file)
 {
-  long long b = *(reinterpret_cast<long long*>(&l));
+  long long b = *(copy_reinterpret_cast<long long*>(&l));
   int b1, b2, b3, b4, b5, b6, b7, b8;
 
   // Little endian.
--- a/laf/base/mem_utils.h
+++ b/laf/base/mem_utils.h
@@ -8,10 +8,18 @@
 #define BASE_MEM_UTILS_H_INCLUDED
 #pragma once
 
+#include <cstring>
 #include <string>
 
 namespace base {
 
+  template<typename T>
+  T copy_reinterpret_cast(const void* ptr) {
+    T tmp;
+    std::memcpy(&tmp, ptr, sizeof(T));
+    return tmp;
+  }
+
   std::string get_pretty_memory_size(std::size_t memsize);
 
 } // namespace base
--- a/laf/base/serialization.cpp
+++ b/laf/base/serialization.cpp
@@ -8,6 +8,7 @@
 #include "config.h"
 #endif
 
+#include "base/mem_utils.h"
 #include "base/serialization.h"
 
 #include <iostream>
@@ -57,7 +58,7 @@ std::ostream& little_endian::write64(std::ostream& os, uint64_t qword)
 
 std::ostream& little_endian::write_float(std::ostream& os, float value)
 {
-  int b = *(reinterpret_cast<int*>(&value));
+  int b = *(copy_reinterpret_cast<int*>(&value));
   os.put((int)((b & 0x000000ffl)));
   os.put((int)((b & 0x0000ff00l) >> 8));
   os.put((int)((b & 0x00ff0000l) >> 16));
@@ -67,7 +68,7 @@ std::ostream& little_endian::write_float(std::ostream& os, float value)
 
 std::ostream& little_endian::write_double(std::ostream& os, double value)
 {
-  long long b = *(reinterpret_cast<long long*>(&value));
+  long long b = *(copy_reinterpret_cast<long long*>(&value));
   os.put((int)((b & 0x00000000000000ffl)));
   os.put((int)((b & 0x000000000000ff00l) >> 8));
   os.put((int)((b & 0x0000000000ff0000l) >> 16));
@@ -126,7 +127,7 @@ float little_endian::read_float(std::istream& is)
   b3 = is.get();
   b4 = is.get();
   int v = ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
-  return *reinterpret_cast<float*>(&v);
+  return *copy_reinterpret_cast<float*>(&v);
 }
 
 double little_endian::read_double(std::istream& is)
@@ -148,7 +149,7 @@ double little_endian::read_double(std::istream& is)
            ((long long)b3 << 16) |
            ((long long)b2 << 8) |
            (long long)b1);
-  return *reinterpret_cast<double*>(&v);
+  return *copy_reinterpret_cast<double*>(&v);
 }
 
 std::ostream& big_endian::write16(std::ostream& os, uint16_t word)
@@ -182,7 +183,7 @@ std::ostream& big_endian::write64(std::ostream& os, uint64_t qword)
 
 std::ostream& big_endian::write_float(std::ostream& os, float value)
 {
-  int b = *(reinterpret_cast<int*>(&value));
+  int b = *(copy_reinterpret_cast<int*>(&value));
   os.put((int)((b & 0xff000000l) >> 24));
   os.put((int)((b & 0x00ff0000l) >> 16));
   os.put((int)((b & 0x0000ff00l) >> 8));
@@ -192,7 +193,7 @@ std::ostream& big_endian::write_float(std::ostream& os, float value)
 
 std::ostream& big_endian::write_double(std::ostream& os, double value)
 {
-  long long b = *(reinterpret_cast<long long*>(&value));
+  long long b = *(copy_reinterpret_cast<long long*>(&value));
   os.put((int)((b & 0xff00000000000000l) >> 56));
   os.put((int)((b & 0x00ff000000000000l) >> 48));
   os.put((int)((b & 0x0000ff0000000000l) >> 40));
@@ -251,7 +252,7 @@ float big_endian::read_float(std::istream& is)
   b2 = is.get();
   b1 = is.get();
   int v = ((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
-  return *reinterpret_cast<float*>(&v);
+  return *copy_reinterpret_cast<float*>(&v);
 }
 
 double big_endian::read_double(std::istream& is)
@@ -273,7 +274,7 @@ double big_endian::read_double(std::istream& is)
            ((long long)b3 << 16) |
            ((long long)b2 << 8) |
            (long long)b1);
-  return *reinterpret_cast<double*>(&v);
+  return *copy_reinterpret_cast<double*>(&v);
 }
 
 
