Skip to content

Commit 29e821d

Browse files
authored
Merge pull request #3493 from pygame-community/ankith26-sanitizers
Add sanitize flag to dev.py, fix UBSAN issues and run UBSAN check on CI
2 parents d5e66d8 + 4fd09eb commit 29e821d

File tree

11 files changed

+75
-45
lines changed

11 files changed

+75
-45
lines changed

.github/workflows/run-ubuntu-checks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ jobs:
101101
id: build-pygame-ce
102102
run: |
103103
pyenv global ${{ matrix.python }}-debug
104-
python dev.py build --lax --coverage
104+
python dev.py build --lax --coverage --sanitize undefined
105105
106106
- name: Run tests
107107
env:

dev.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
from pathlib import Path
1616
from typing import Any, Union
1717

18+
from buildconfig.get_version import version
19+
1820
MOD_NAME = "pygame-ce"
1921
DIST_DIR = "dist"
2022

@@ -204,9 +206,11 @@ def __init__(self) -> None:
204206

205207
def cmd_build(self):
206208
wheel_dir = self.args.get("wheel", DIST_DIR)
209+
quiet = self.args.get("quiet", False)
207210
debug = self.args.get("debug", False)
208211
lax = self.args.get("lax", False)
209212
sdl3 = self.args.get("sdl3", False)
213+
sanitize = self.args.get("sanitize")
210214
coverage = self.args.get("coverage", False)
211215
if wheel_dir and coverage:
212216
pprint("Cannot pass --wheel and --coverage together", Colors.RED)
@@ -228,6 +232,8 @@ def cmd_build(self):
228232

229233
if not wheel_dir:
230234
# editable install
235+
if not quiet:
236+
install_args.append("-Ceditable-verbose=true")
231237
install_args.append("--editable")
232238

233239
install_args.append(".")
@@ -245,15 +251,19 @@ def cmd_build(self):
245251
if coverage:
246252
install_args.extend(COVERAGE_ARGS)
247253

254+
if sanitize:
255+
install_args.append(f"-Csetup-args=-Db_sanitize={sanitize}")
256+
248257
info_str = f"with {debug=}, {lax=}, {sdl3=}, and {coverage=}"
249258
if wheel_dir:
250259
pprint(f"Building wheel at '{wheel_dir}' ({info_str})")
251260
cmd_run(
252261
[self.py, "-m", "pip", "wheel", "-v", "-w", wheel_dir, *install_args]
253262
)
254263
pprint("Installing wheel")
264+
mod_name = f"{MOD_NAME}=={version}"
255265
pip_install(
256-
self.py, ["--no-index", "--force", "--find-links", wheel_dir, MOD_NAME]
266+
self.py, ["--no-index", "--force", "--find-links", wheel_dir, mod_name]
257267
)
258268
else:
259269
pprint(f"Installing in editable mode ({info_str})")
@@ -352,6 +362,11 @@ def parse_args(self):
352362
f"wheel (if not passed, '{DIST_DIR}' is used)"
353363
),
354364
)
365+
build_parser.add_argument(
366+
"--quiet",
367+
action="store_true",
368+
help="Silence build log in editable install (doing editable-verbose=false)",
369+
)
355370
build_parser.add_argument(
356371
"--debug",
357372
action="store_true",
@@ -367,6 +382,20 @@ def parse_args(self):
367382
action="store_true",
368383
help="Build against SDL3 instead of the default SDL2",
369384
)
385+
build_parser.add_argument(
386+
"--sanitize",
387+
choices=[
388+
"address",
389+
"undefined",
390+
"address,undefined",
391+
"leak",
392+
"thread",
393+
"memory",
394+
"none",
395+
],
396+
default="none",
397+
help="Enable compiler sanitizers. Defaults to 'none'.",
398+
)
370399
build_parser.add_argument(
371400
"--coverage",
372401
action="store_true",

src_c/SDL_gfx/SDL_gfxPrimitives.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2782,7 +2782,7 @@ _aalineColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
27822782
/*
27832783
* Not-so-portable version: erradj = ((Uint64)dx << 32) / (Uint64)dy;
27842784
*/
2785-
erradj = ((dx << 16) / dy) << 16;
2785+
erradj = (Uint32)((dx << 16) / dy) << 16;
27862786

27872787
/*
27882788
* draw all pixels other than the first and last
@@ -2819,7 +2819,7 @@ _aalineColor(SDL_Surface *dst, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2,
28192819
/*
28202820
* Not-so-portable version: erradj = ((Uint64)dy << 32) / (Uint64)dx;
28212821
*/
2822-
erradj = ((dy << 16) / dx) << 16;
2822+
erradj = (Uint32)((dy << 16) / dx) << 16;
28232823

28242824
/*
28252825
* draw all pixels other than the first and last

src_c/alphablit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2448,7 +2448,7 @@ alphablit_alpha(SDL_BlitInfo *info)
24482448
int srcbpp = PG_FORMAT_BytesPerPixel(srcfmt);
24492449
int dstbpp = PG_FORMAT_BytesPerPixel(dstfmt);
24502450
Uint8 dR, dG, dB, dA, sR, sG, sB, sA;
2451-
int dRi, dGi, dBi, dAi, sRi, sGi, sBi, sAi;
2451+
Uint32 dRi, dGi, dBi, dAi, sRi, sGi, sBi, sAi;
24522452
Uint32 modulateA = info->src_blanket_alpha;
24532453
Uint32 pixel;
24542454

src_c/color.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,7 +1737,7 @@ _color_inv(pgColorObject *color)
17371737
static PyObject *
17381738
_color_int(pgColorObject *color)
17391739
{
1740-
Uint32 tmp = (color->data[0] << 24) + (color->data[1] << 16) +
1740+
Uint32 tmp = ((Uint32)color->data[0] << 24) + (color->data[1] << 16) +
17411741
(color->data[2] << 8) + color->data[3];
17421742
return PyLong_FromUnsignedLong(tmp);
17431743
}
@@ -1748,7 +1748,7 @@ _color_int(pgColorObject *color)
17481748
static PyObject *
17491749
_color_float(pgColorObject *color)
17501750
{
1751-
Uint32 tmp = ((color->data[0] << 24) + (color->data[1] << 16) +
1751+
Uint32 tmp = (((Uint32)color->data[0] << 24) + (color->data[1] << 16) +
17521752
(color->data[2] << 8) + color->data[3]);
17531753
return PyFloat_FromDouble((double)tmp);
17541754
}

src_c/freetype/ft_wrap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@
4141
#define FX6_TRUNC(x) ((x) >> 6)
4242
#define FX16_CEIL_TO_FX6(x) (((x) + 1023L) >> 10)
4343
#define FX16_ROUND_TO_INT(x) (((x) + 32768L) >> 16)
44-
#define INT_TO_FX6(i) ((FT_Fixed)((i) << 6))
45-
#define INT_TO_FX16(i) ((FT_Fixed)((i) << 16))
44+
#define INT_TO_FX6(i) ((FT_Fixed)((unsigned long long)(i) << 6))
45+
#define INT_TO_FX16(i) ((FT_Fixed)((unsigned long long)(i) << 16))
4646
#define FX16_TO_DBL(x) ((x) * 1.52587890625e-5 /* 2.0^-16 */)
4747
#define DBL_TO_FX16(d) ((FT_Fixed)((d) * 65536.0))
4848
#define FX6_TO_DBL(x) ((x) * 1.5625e-2 /* 2.0^-6 */)

src_c/mask.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,8 @@ set_pixel_color(Uint8 *pixel, Uint8 bpp, Uint32 color)
763763

764764
case 3:
765765
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
766-
*(Uint16 *)pixel = color;
766+
pixel[0] = color;
767+
pixel[1] = color >> 8;
767768
pixel[2] = color >> 16;
768769
#else /* != SDL_LIL_ENDIAN */
769770
pixel[2] = color;

src_c/pixelcopy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ array_to_surface(PyObject *self, PyObject *arg)
734734
else {
735735
Uint32 alpha = 0;
736736
if (format->Amask) {
737-
alpha = 255 >> Aloss << Ashift;
737+
alpha = 255u >> Aloss << Ashift;
738738
}
739739
switch (view_p->itemsize) {
740740
case sizeof(Uint8):

src_c/rotozoom.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ transformSurfaceRGBA(SDL_Surface *src, SDL_Surface *dst, int cx, int cy,
236236
/*
237237
* Variable setup
238238
*/
239-
xd = ((src->w - dst->w) << 15);
240-
yd = ((src->h - dst->h) << 15);
239+
xd = ((unsigned long long)(src->w - dst->w) << 15);
240+
yd = ((unsigned long long)(src->h - dst->h) << 15);
241241
ax = (cx << 16) - (icos * cx);
242242
ay = (cy << 16) - (isin * cx);
243243
sw = src->w - 1;

src_c/surface.c

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -717,16 +717,16 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
717717
if (flags & PGS_SRCALPHA) {
718718
switch (bpp) {
719719
case 16:
720-
Rmask = 0xF << 8;
721-
Gmask = 0xF << 4;
722-
Bmask = 0xF;
723-
Amask = 0xF << 12;
720+
Rmask = 0xFu << 8;
721+
Gmask = 0xFu << 4;
722+
Bmask = 0xFu;
723+
Amask = 0xFu << 12;
724724
break;
725725
case 32:
726-
Rmask = 0xFF << 16;
727-
Gmask = 0xFF << 8;
728-
Bmask = 0xFF;
729-
Amask = 0xFF << 24;
726+
Rmask = 0xFFu << 16;
727+
Gmask = 0xFFu << 8;
728+
Bmask = 0xFFu;
729+
Amask = 0xFFu << 24;
730730
break;
731731
default:
732732
PyErr_SetString(
@@ -793,20 +793,20 @@ surface_init(pgSurfaceObject *self, PyObject *args, PyObject *kwds)
793793
if (flags & PGS_SRCALPHA) {
794794
switch (bpp) {
795795
case 16:
796-
Rmask = 0xF << 8;
797-
Gmask = 0xF << 4;
798-
Bmask = 0xF;
799-
Amask = 0xF << 12;
796+
Rmask = 0xFu << 8;
797+
Gmask = 0xFu << 4;
798+
Bmask = 0xFu;
799+
Amask = 0xFu << 12;
800800
break;
801801
case 24:
802802
bpp = 32;
803803
// we automatically step up to 32 if video is 24, fall
804804
// through to case below
805805
case 32:
806-
Rmask = 0xFF << 16;
807-
Gmask = 0xFF << 8;
808-
Bmask = 0xFF;
809-
Amask = 0xFF << 24;
806+
Rmask = 0xFFu << 16;
807+
Gmask = 0xFFu << 8;
808+
Bmask = 0xFFu;
809+
Amask = 0xFFu << 24;
810810
break;
811811
default:
812812
PyErr_SetString(

0 commit comments

Comments
 (0)