← Back to team overview

linuxdcpp-team team mailing list archive

[Branch ~linuxdcpp-team/linuxdcpp/trunk] Rev 346: Added SIGBUS handler for fastHash

 

------------------------------------------------------------
revno: 346
committer: Razzloss <razzloss@xxxxxxxxx>
branch nick: master
timestamp: Thu 2010-01-07 21:49:29 +0200
message:
  Added SIGBUS handler for fastHash
modified:
  Changelog.txt
  dcpp/HashManager.cpp


--
lp:linuxdcpp
https://code.launchpad.net/~linuxdcpp-team/linuxdcpp/trunk

Your team LinuxDC++ Team is subscribed to branch lp:linuxdcpp.
To unsubscribe from this branch go to https://code.launchpad.net/~linuxdcpp-team/linuxdcpp/trunk/+edit-subscription.
=== modified file 'Changelog.txt'
--- Changelog.txt	2010-01-01 00:57:24 +0000
+++ Changelog.txt	2010-01-07 19:49:29 +0000
@@ -40,6 +40,7 @@
 [2009-11-02] Bumped minimum scons version to 0.98.1 to resolve multiple building issues. (Steven)
 [2009-11-25] Added issue with MacPorts boost lib not being detected on OS X to Readme. (thanks vszakats)
 [2009-12-31] lp#397365: Fixed sorting of "Time Left" column in transfers view. (Steven)
+[2010-01-07] lp#473173: Crash when hashing files. Added missing SIGBUS handler. (Razzloss)
 
 *** 1.0.3 2009-02-01 ***
 [2008-08-10] lp#256236: Fixed a crash on startup when using auto-open options.

=== modified file 'dcpp/HashManager.cpp'
--- dcpp/HashManager.cpp	2009-08-15 04:40:26 +0000
+++ dcpp/HashManager.cpp	2010-01-07 19:49:29 +0000
@@ -28,6 +28,8 @@
 
 #ifndef _WIN32
 #include <sys/mman.h> // mmap, munmap, madvise
+#include <signal.h>  // for handling read errors from previous trio
+#include <setjmp.h>  
 #endif
 
 namespace dcpp {
@@ -600,6 +602,13 @@
 
 #else // !_WIN32
 static const int64_t BUF_SIZE = 0x1000000 - (0x1000000 % getpagesize());
+static sigjmp_buf sb_env;
+
+static void sigbus_handler(int signum, siginfo_t* info, void* context) {
+	// Jump back to the fastHash which will return error
+	if (signum == SIGBUS && (info->si_code == BUS_ADRERR || info->si_code == BUS_OBJERR))	// Apparently truncating file in Solaris sets si_code to BUS_OBJERR
+		siglongjmp(sb_env, 1);
+}
 
 bool HashManager::Hasher::fastHash(const string& filename, uint8_t* , TigerTree& tth, int64_t size, CRC32Filter* xcrc32) {
 	int fd = open(Text::fromUtf8(filename).c_str(), O_RDONLY);
@@ -611,6 +620,24 @@
 	int64_t size_read = 0;
 	void *buf = 0;
 
+	// Prepare and setup a signal handler in case of SIGBUS during mmapped file reads.
+	// SIGBUS can be sent when the file is truncated or in case of read errors.	 
+	struct sigaction act, oldact;
+	sigset_t signalset;
+
+	sigemptyset(&signalset);
+
+	act.sa_handler = NULL;
+	act.sa_sigaction = sigbus_handler;
+	act.sa_mask = signalset;
+	act.sa_flags = SA_SIGINFO | SA_RESETHAND;
+
+	if (sigaction(SIGBUS, &act, &oldact) == -1) {
+		dcdebug("Failed to set signal handler for fastHash\n");
+		close(fd);
+		return false;	// Better luck with the slow hash.
+	}
+
 	uint32_t lastRead = GET_TICK();
 	while(pos <= size) {
 		if(size_left > 0) {
@@ -621,6 +648,18 @@
 				return false;
 			}
 
+			if (sigsetjmp(sb_env, 1)) {
+				if (buf != 0) {
+					munmap(buf, size_read);
+				}
+				if (sigaction(SIGBUS, &oldact, NULL) == -1) {
+					dcdebug("Failed to reset old signal handler for SIGBUS\n");
+				}
+	
+				close(fd);
+				return false;
+			}
+
 			madvise(buf, size_read, MADV_SEQUENTIAL | MADV_WILLNEED);
 
 			if(SETTING(MAX_HASH_SPEED) > 0) {
@@ -656,6 +695,11 @@
 		size_left -= size_read;
 	}
 	close(fd);
+
+	if (sigaction(SIGBUS, &oldact, NULL) == -1) {
+		dcdebug("Failed to reset old signal handler for SIGBUS\n");
+	}
+
 	return true;
 }