Skip to content

Commit f0d7922

Browse files
authored
Merge pull request libgit2#5583 from 0xdky/dhruva/build-with-nommap
Build with NO_MMAP
2 parents fa01786 + 4fafe9f commit f0d7922

File tree

6 files changed

+152
-9
lines changed

6 files changed

+152
-9
lines changed

.github/workflows/nightly.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ jobs:
9696
ASAN_SYMBOLIZER_PATH: /usr/bin/llvm-symbolizer-10
9797
TSAN_OPTIONS: suppressions=/home/libgit2/source/script/thread-sanitizer.supp second_deadlock_stack=1
9898
os: ubuntu-latest
99+
- # Focal, Clang 10, mmap emulation (NO_MMAP)
100+
container:
101+
name: focal
102+
env:
103+
CC: clang-10
104+
CFLAGS: -DNO_MMAP
105+
CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=/usr/local
106+
CMAKE_GENERATOR: Ninja
107+
SKIP_SSH_TESTS: true
108+
SKIP_NEGOTIATE_TESTS: true
109+
os: ubuntu-latest
99110
- # macOS
100111
os: macos-10.15
101112
env:
@@ -114,6 +125,15 @@ jobs:
114125
CMAKE_OPTIONS: -A x64 -DWIN32_LEAKCHECK=ON -DDEPRECATE_HARD=ON
115126
SKIP_SSH_TESTS: true
116127
SKIP_NEGOTIATE_TESTS: true
128+
- # Windows amd64 Visual Studio (NO_MMAP)
129+
os: windows-2019
130+
env:
131+
ARCH: amd64
132+
CMAKE_GENERATOR: Visual Studio 16 2019
133+
CFLAGS: -DNO_MMAP
134+
CMAKE_OPTIONS: -A x64 -DDEPRECATE_HARD=ON
135+
SKIP_SSH_TESTS: true
136+
SKIP_NEGOTIATE_TESTS: true
117137
- # Windows x86 Visual Studio
118138
os: windows-2019
119139
env:

src/indexer.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,23 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
603603

604604
static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
605605
{
606+
#ifdef NO_MMAP
607+
size_t remaining_size = size;
608+
const char *ptr = (const char *)data;
609+
610+
/* Handle data size larger that ssize_t */
611+
while (remaining_size > 0) {
612+
ssize_t nb;
613+
HANDLE_EINTR(nb, p_pwrite(idx->pack->mwf.fd, (void *)ptr,
614+
remaining_size, offset));
615+
if (nb <= 0)
616+
return -1;
617+
618+
ptr += nb;
619+
offset += nb;
620+
remaining_size -= nb;
621+
}
622+
#else
606623
git_file fd = idx->pack->mwf.fd;
607624
size_t mmap_alignment;
608625
size_t page_offset;
@@ -627,6 +644,7 @@ static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t s
627644
map_data = (unsigned char *)map.data;
628645
memcpy(map_data + page_offset, data, size);
629646
p_munmap(&map);
647+
#endif
630648

631649
return 0;
632650
}

src/posix.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,24 +238,43 @@ int git__mmap_alignment(size_t *alignment)
238238

239239
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
240240
{
241+
const char *ptr;
242+
size_t remaining_len;
243+
241244
GIT_MMAP_VALIDATE(out, len, prot, flags);
242245

243-
out->data = NULL;
244-
out->len = 0;
246+
/* writes cannot be emulated without handling pagefaults since write happens by
247+
* writing to mapped memory */
248+
if (prot & GIT_PROT_WRITE) {
249+
git_error_set(GIT_ERROR_OS, "trying to map %s-writeable",
250+
((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) ? "shared": "private");
251+
return -1;
252+
}
245253

246-
if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) {
247-
git_error_set(GIT_ERROR_OS, "trying to map shared-writeable");
254+
if (!git__is_ssizet(len)) {
255+
errno = EINVAL;
248256
return -1;
249257
}
250258

259+
out->len = 0;
251260
out->data = git__malloc(len);
252261
GIT_ERROR_CHECK_ALLOC(out->data);
253262

254-
if (!git__is_ssizet(len) ||
255-
(p_lseek(fd, offset, SEEK_SET) < 0) ||
256-
(p_read(fd, out->data, len) != (ssize_t)len)) {
257-
git_error_set(GIT_ERROR_OS, "mmap emulation failed");
258-
return -1;
263+
remaining_len = len;
264+
ptr = (const char *)out->data;
265+
while (remaining_len > 0) {
266+
ssize_t nb;
267+
HANDLE_EINTR(nb, p_pread(fd, (void *)ptr, remaining_len, offset));
268+
if (nb <= 0) {
269+
git_error_set(GIT_ERROR_OS, "mmap emulation failed");
270+
git__free(out->data);
271+
out->data = NULL;
272+
return -1;
273+
}
274+
275+
ptr += nb;
276+
offset += nb;
277+
remaining_len -= nb;
259278
}
260279

261280
out->len = len;
@@ -267,6 +286,10 @@ int p_munmap(git_map *map)
267286
GIT_ASSERT_ARG(map);
268287
git__free(map->data);
269288

289+
/* Initializing will help debug use-after-free */
290+
map->len = 0;
291+
map->data = NULL;
292+
270293
return 0;
271294
}
272295

src/posix.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@
8989
#define EAFNOSUPPORT (INT_MAX-1)
9090
#endif
9191

92+
/* Compiler independent macro to handle signal interrpted system calls */
93+
#define HANDLE_EINTR(result, x) do { \
94+
result = (x); \
95+
} while (result == -1 && errno == EINTR);
96+
97+
9298
/* Provide a 64-bit size for offsets. */
9399

94100
#if defined(_MSC_VER)
@@ -119,6 +125,9 @@ typedef int git_file;
119125
extern ssize_t p_read(git_file fd, void *buf, size_t cnt);
120126
extern int p_write(git_file fd, const void *buf, size_t cnt);
121127

128+
extern ssize_t p_pread(int fd, void *data, size_t size, off64_t offset);
129+
extern ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset);
130+
122131
#define p_close(fd) close(fd)
123132
#define p_umask(m) umask(m)
124133

src/unix/posix.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,7 @@ GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2])
101101
# define p_futimes futimes
102102
#endif
103103

104+
#define p_pread(f, d, s, o) pread(f, d, s, o)
105+
#define p_pwrite(f, d, s, o) pwrite(f, d, s, o)
106+
104107
#endif

src/win32/posix_w32.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,3 +981,73 @@ int p_inet_pton(int af, const char *src, void *dst)
981981
errno = EINVAL;
982982
return -1;
983983
}
984+
985+
ssize_t p_pread(int fd, void *data, size_t size, off64_t offset)
986+
{
987+
HANDLE fh;
988+
DWORD rsize = 0;
989+
OVERLAPPED ov = {0};
990+
LARGE_INTEGER pos = {0};
991+
off64_t final_offset = 0;
992+
993+
/* Fail if the final offset would have overflowed to match POSIX semantics. */
994+
if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
995+
errno = EINVAL;
996+
return -1;
997+
}
998+
999+
/*
1000+
* Truncate large writes to the maximum allowable size: the caller
1001+
* needs to always call this in a loop anyways.
1002+
*/
1003+
if (size > INT32_MAX) {
1004+
size = INT32_MAX;
1005+
}
1006+
1007+
pos.QuadPart = offset;
1008+
ov.Offset = pos.LowPart;
1009+
ov.OffsetHigh = pos.HighPart;
1010+
fh = (HANDLE)_get_osfhandle(fd);
1011+
1012+
if (ReadFile(fh, data, (DWORD)size, &rsize, &ov)) {
1013+
return (ssize_t)rsize;
1014+
}
1015+
1016+
set_errno();
1017+
return -1;
1018+
}
1019+
1020+
ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset)
1021+
{
1022+
HANDLE fh;
1023+
DWORD wsize = 0;
1024+
OVERLAPPED ov = {0};
1025+
LARGE_INTEGER pos = {0};
1026+
off64_t final_offset = 0;
1027+
1028+
/* Fail if the final offset would have overflowed to match POSIX semantics. */
1029+
if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
1030+
errno = EINVAL;
1031+
return -1;
1032+
}
1033+
1034+
/*
1035+
* Truncate large writes to the maximum allowable size: the caller
1036+
* needs to always call this in a loop anyways.
1037+
*/
1038+
if (size > INT32_MAX) {
1039+
size = INT32_MAX;
1040+
}
1041+
1042+
pos.QuadPart = offset;
1043+
ov.Offset = pos.LowPart;
1044+
ov.OffsetHigh = pos.HighPart;
1045+
fh = (HANDLE)_get_osfhandle(fd);
1046+
1047+
if (WriteFile(fh, data, (DWORD)size, &wsize, &ov)) {
1048+
return (ssize_t)wsize;
1049+
}
1050+
1051+
set_errno();
1052+
return -1;
1053+
}

0 commit comments

Comments
 (0)