Skip to content

Commit b9530a8

Browse files
committed
Support additional memory protection flag combinations
1 parent b6e8595 commit b9530a8

File tree

1 file changed

+42
-30
lines changed

1 file changed

+42
-30
lines changed

Src/IronPython.Modules/mmap.cs

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -68,40 +68,65 @@ private static Exception WindowsError(int code) {
6868
public static PythonType mmap {
6969
get {
7070
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
71-
return DynamicHelpers.GetPythonTypeFromType(typeof(MmapDefault));
71+
return DynamicHelpers.GetPythonTypeFromType(typeof(MmapWindows));
7272
}
7373

7474
return DynamicHelpers.GetPythonTypeFromType(typeof(MmapUnix));
7575
}
7676
}
7777

78+
7879
[PythonType("mmap"), PythonHidden]
7980
public class MmapUnix : MmapDefault {
8081
public MmapUnix(CodeContext/*!*/ context, int fileno, long length, int flags = MAP_SHARED, int prot = PROT_WRITE | PROT_READ, int access = ACCESS_DEFAULT, long offset = 0)
81-
: base(context, fileno, length, null, NormalizeAccess(flags, prot, access), offset) { }
82+
: base(context, fileno, length, null, ToMmapFileAccess(flags, prot, access), offset) { }
8283

83-
private static int NormalizeAccess(int flags, int prot, int access) {
84+
private static MemoryMappedFileAccess ToMmapFileAccess(int flags, int prot, int access) {
8485
if (access == ACCESS_DEFAULT) {
8586
if ((flags & (MAP_PRIVATE | MAP_SHARED)) == 0) {
8687
throw PythonOps.OSError(PythonErrorNumber.EINVAL, "Invalid argument");
8788
}
8889
if ((prot & PROT_WRITE) != 0) {
89-
return (flags & MAP_PRIVATE) != 0 ? ACCESS_COPY : ACCESS_WRITE;
90-
}
91-
if ((prot & PROT_READ) != 0) {
92-
return ACCESS_READ;
93-
}
94-
throw PythonOps.NotImplementedError("this combination of flags and prot is not supported");
90+
prot |= PROT_READ;
91+
}
92+
return (prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) switch {
93+
PROT_READ => MemoryMappedFileAccess.Read,
94+
PROT_READ | PROT_WRITE => (flags & MAP_PRIVATE) == 0 ? MemoryMappedFileAccess.ReadWrite : MemoryMappedFileAccess.CopyOnWrite,
95+
PROT_READ | PROT_EXEC => MemoryMappedFileAccess.ReadExecute,
96+
PROT_READ | PROT_WRITE | PROT_EXEC when (flags & MAP_PRIVATE) == 0 => MemoryMappedFileAccess.ReadWriteExecute,
97+
_ => throw PythonOps.NotImplementedError("this combination of prot is not supported"),
98+
};
9599
} else if (flags != MAP_SHARED || prot != (PROT_WRITE | PROT_READ)) {
96100
throw PythonOps.ValueError("mmap can't specify both access and flags, prot.");
97-
} else if (access != ACCESS_READ && access != ACCESS_WRITE && access != ACCESS_COPY) {
98-
throw PythonOps.ValueError("mmap invalid access parameter");
101+
} else {
102+
return access switch {
103+
ACCESS_READ => MemoryMappedFileAccess.Read,
104+
ACCESS_WRITE => MemoryMappedFileAccess.ReadWrite,
105+
ACCESS_COPY => MemoryMappedFileAccess.CopyOnWrite,
106+
_ => throw PythonOps.ValueError("mmap invalid access parameter"),
107+
};
99108
}
100-
return access;
101109
}
102110
}
103111

112+
104113
[PythonType("mmap"), PythonHidden]
114+
public class MmapWindows : MmapDefault {
115+
public MmapWindows(CodeContext context, int fileno, long length, string tagname = null, int access = ACCESS_DEFAULT, long offset = 0)
116+
: base(context, fileno, length, tagname, ToMmapFileAccess(access), offset) { }
117+
118+
private static MemoryMappedFileAccess ToMmapFileAccess(int access) {
119+
return access switch {
120+
ACCESS_READ => MemoryMappedFileAccess.Read,
121+
// On Windows, default access is write-through
122+
ACCESS_DEFAULT or ACCESS_WRITE => MemoryMappedFileAccess.ReadWrite,
123+
ACCESS_COPY => MemoryMappedFileAccess.CopyOnWrite,
124+
_ => throw PythonOps.ValueError("mmap invalid access parameter"),
125+
};
126+
}
127+
}
128+
129+
[PythonHidden]
105130
public class MmapDefault : IWeakReferenceable {
106131
private MemoryMappedFile _file;
107132
private MemoryMappedViewAccessor _view;
@@ -115,21 +140,8 @@ public class MmapDefault : IWeakReferenceable {
115140
private volatile bool _isClosed;
116141
private int _refCount = 1;
117142

118-
public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tagname = null, int access = ACCESS_DEFAULT, long offset = 0) {
119-
switch (access) {
120-
case ACCESS_READ:
121-
_fileAccess = MemoryMappedFileAccess.Read;
122-
break;
123-
case ACCESS_DEFAULT: // On Windows, default access is write-through
124-
case ACCESS_WRITE:
125-
_fileAccess = MemoryMappedFileAccess.ReadWrite;
126-
break;
127-
case ACCESS_COPY:
128-
_fileAccess = MemoryMappedFileAccess.CopyOnWrite;
129-
break;
130-
default:
131-
throw PythonOps.ValueError("mmap invalid access parameter");
132-
}
143+
public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tagname, MemoryMappedFileAccess fileAccess, long offset) {
144+
_fileAccess = fileAccess;
133145

134146
if (length < 0) {
135147
throw PythonOps.OverflowError("memory mapped size must be positive");
@@ -175,7 +187,7 @@ public MmapDefault(CodeContext/*!*/ context, int fileno, long length, string tag
175187
throw PythonOps.OSError(PythonExceptions._OSError.ERROR_INVALID_BLOCK, "Bad file descriptor");
176188
}
177189

178-
if (_fileAccess == MemoryMappedFileAccess.ReadWrite && !_sourceStream.CanWrite) {
190+
if (_fileAccess is MemoryMappedFileAccess.ReadWrite or MemoryMappedFileAccess.ReadWriteExecute && !_sourceStream.CanWrite) {
179191
throw WindowsError(PythonExceptions._OSError.ERROR_ACCESS_DENIED);
180192
}
181193

@@ -579,7 +591,7 @@ public string readline() {
579591

580592
public void resize(long newsize) {
581593
using (new MmapLocker(this)) {
582-
if (_fileAccess != MemoryMappedFileAccess.ReadWrite) {
594+
if (_fileAccess is not MemoryMappedFileAccess.ReadWrite and not MemoryMappedFileAccess.ReadWriteExecute) {
583595
throw PythonOps.TypeError("mmap can't resize a readonly or copy-on-write memory map.");
584596
}
585597

@@ -802,7 +814,7 @@ private long Position {
802814
}
803815

804816
private void EnsureWritable() {
805-
if (_fileAccess == MemoryMappedFileAccess.Read) {
817+
if (_fileAccess is MemoryMappedFileAccess.Read or MemoryMappedFileAccess.ReadExecute) {
806818
throw PythonOps.TypeError("mmap can't modify a read-only memory map.");
807819
}
808820
}

0 commit comments

Comments
 (0)