Thread: Wierd bug in bignum left shift function

  1. #16
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Quote Originally Posted by laserlight View Post
    It's not clear to me how that attack would work in practice without leveraging on another vulnerability, e.g., a typical buffer overflow vulnerability.

    So no, I don't think this warrants dispensing with good software engineering practice in favour of more difficult to understand long blocks of code that itself could lead to bugs, possibly security vulnerabilities.
    Then we agree to disagree on this one

  2. #17
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,157
    Well, I'm clearly not the only one who disagrees with you: the experts on the C and C++ standards committees disagree with you that this constitutes a significant attack vector. If not, it would be a simple matter to do a great deal to fix it: make static inline functions (and for C++, inline functions defined in unnamed namespaces) truly forced inline, such that they can always be removed from the symbol table. These are functions that typically don't do additional checking of parameters since they are almost always implementation detail called by functions that do do parameter checking. (Granted, C++ also has private member functions that cannot always be inlined, but surely they would have at least reached for low hanging fruit if this were truly an issue.)
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #18
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    I'm gonna put aside my disagreement with lazerlight since it is pointless to argue about something I'm gonna be stubborn about, instead I'd like some help identifing potential causes of 2 problem results (both rely on same function at deepest level).
    Code:
    int __alu_div( alu_t *alu, int num, int val, int rem )
    {
    	int ret = _alu_check3( alu, num, val, rem ), cmp = 0;
    	alu_reg_t *N, *R;
    	alu_bit_t n;
    	alu_seg_t state;
    	size_t bits = 0, bit;
    	
    	if ( ret != 0 )
    		return ret;
    		
    	N = alu->regv + num;
    	R = alu->regv + rem;
    	
    	memcpy( R->part, N->part, alu->buff.perN );
    	
    	ret = _alu_end_bit( alu, rem, &(n) );
    	for (
    		R->init = R->last;
    		R->init.b;
    		++bits, R->init = alu_bit_dec(R->init)
    	)
    	{
    		ret = _alu_cmp( alu, rem, val, &cmp, &bit );
    		if ( cmp >= 0 )
    		{
    			state = *(n.S);
    			_alu_sub( alu, rem, val );
    			if ( *(n.S) == state )
    				break;
    			__alu_shl( alu, num, bits );
    			*(N->init.S) |= 1;
    			bits = 0;
    		}
    	}
    	__alu_shl( alu, num, bits );
    	alu_reset_reg( alu, rem, 0 );
    	
    	return 0;
    }
    
    int _alu_div( alu_t *alu, int num, int val )
    {
    	int tmp = -1, ret = alu_get_reg( alu, &tmp );
    	
    	if ( ret != 0 )
    	{
    		alu_error( ret );
    		return ret;
    	}
    	
    	ret = __alu_div( alu, num, val, tmp );
    	alu_rem_reg( alu, tmp );
    	
    	return ret;
    }
    
    int _alu_rem( alu_t *alu, int num, int val )
    {
    	int tmp = -1, ret = alu_get_reg( alu, &tmp );
    	alu_reg_t *N, *T;
    	
    	if ( ret != 0 )
    	{
    		alu_error( ret );
    		return ret;
    	}
    	
    	ret = __alu_div( alu, num, val, tmp );
    	
    	if ( ret != 0 )
    	{
    		alu_rem_reg( alu, tmp );
    		alu_error( ret );
    		return ret;
    	}
    	
    	N = alu->regv + num;
    	T = alu->regv + tmp;
    	(void)memcpy( N->part, T->part, alu->buff.perN );
    	
    	(void)alu_rem_reg( alu, tmp );
    	
    	return 0;
    }
    The output:
    Code:
    ...
    ./alu.AppImage
    test.c:157: main() 'Initiating ALU to 0...'
    test.c:165: main() 'Requesting register for number to modify...'
    test.c:174: main() 'Requesting register for value to modify by...'
    test.c:183: main() 'Comparing values...'
    test.c:50: compare() Expected 1, Got 1
    test.c:50: compare() Expected 0, Got 0
    test.c:50: compare() Expected -1, Got -1
    test.c:189: main() 'Adding values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected DEADC0DF, Got DEADC0DF, op = 'i'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected DEADC0E0, Got DEADC0E0, op = '+'
    test.c:193: main() 'Subtracting values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected DEADC0DD, Got DEADC0DD, op = 'd'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected DEADC0DC, Got DEADC0DC, op = '-'
    test.c:197: main() 'Shifting values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected 7AB70378, Got 7AB70378, op = '<'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected 37AB7037, Got 37AB7037, op = '>'
    test.c:201: main() 'Multiplying value...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected BD5B81BC, Got BD5B81BC, op = '*'
    test.c:204: main() 'Dividing values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected 6F56E06F, Got 00000000, op = '/'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected 00000000, Got DEADC0DE, op = '%'
    Compilation finished successfully.
    As you can see by the last 2 results the division ends prematurely, I've attached the project in it's entirety in case anyone thinks the problem is elsewhere or just wants to check the definitions of structs. I'm gonna take a break and probably head to work early.
    Attached Files Attached Files

  4. #19
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,416
    > adds another point of entry via symlnk or whatever it was for malicious software, the fewer points the better
    This is just BS and FUD.

    What you describe only works for dynamic link libraries, where you can spoof your way in by tricking the link/loader to use your malicious symbol instead of the one from an expected loaded library.

    Otherwise, all your 'secure' statically linked executables would be just as vulnerable as everything else.

    If the attacker has that level of control over your program, they won't need a function call to make it happen.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #20
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Quote Originally Posted by Salem View Post
    > adds another point of entry via symlnk or whatever it was for malicious software, the fewer points the better
    This is just BS and FUD.

    What you describe only works for dynamic link libraries, where you can spoof your way in by tricking the link/loader to use your malicious symbol instead of the one from an expected loaded library.

    Otherwise, all your 'secure' statically linked executables would be just as vulnerable as everything else.

    If the attacker has that level of control over your program, they won't need a function call to make it happen.
    But they would if they're trying to disguise the source of the attack which is what I was trying to reduce the potential of, granted I can't do it perfectly but an attempt is still better than nothing in a user's eyes.

  6. #21
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Got a little further in my division function, part of the issue was no doubt a slight fault in my comparison function, fixed now (for reference it didn't account for init.b not being 0), I get a partially correct quotient now but remainder is still wrong, here's what I have now:
    Code:
    int __alu_div( alu_t *alu, int num, int val, int rem )
    {
    	int ret = _alu_check3( alu, num, val, rem ), cmp = 0;
    	alu_reg_t *N, *R;
    	alu_bit_t n;
    	alu_seg_t state;
    	size_t bits = 0, bit;
    	
    	if ( ret != 0 )
    		return ret;
    		
    	N = alu->regv + num;
    	R = alu->regv + rem;
    	
    	memcpy( R->part, N->part, alu->buff.perN );
    	memset( N->part, 0, alu->buff.perN );
    	
    	ret = _alu_end_bit( alu, rem, &(n) );
    	
    	for (
    		R->last = n, R->init = R->last;
    		R->init.b;
    		++bits, R->init = alu_bit_dec(R->init)
    	)
    	{
    		ret = _alu_cmp( alu, rem, val, &cmp, &bit );
    		if ( cmp >= 0 )
    		{
    			state = *(n.S);
    			_alu_sub( alu, rem, val );
    			if ( *(n.S) == state )
    				break;
    			__alu_shl( alu, num, bits );
    			*(N->init.S) |= 1;
    			bits = 0;
    		}
    	}
    	__alu_shl( alu, num, bits );
    	alu_reset_reg( alu, rem, 0 );
    	
    	return 0;
    }
    Perhaps someone will see what I'm currently not
    Edit: Forgot to add output:
    Code:
    ...
    test.c:204: main() 'Dividing values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected 6F56E06F, Got 6F56FFFE, op = '/'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:147: modify() Expected 00000000, Got FFFFC0E2, op = '%'
    Compilation finished successfully.
    Edit 2: For reference here is the comparison function, perhaps I missed something:
    Code:
    int _alu_cmp( alu_t *alu, int num, int val, int *cmp, size_t *bit )
    {
    	int ret = 0, a, b;
    	alu_bit_t n = {0}, v = {0};
    	alu_reg_t *N, *V;
    	size_t ndiff, vdiff;
    	
    	if ( !cmp || !bit )
    	{
    		alu_error( EDESTADDRREQ );
    		return EDESTADDRREQ;
    	}
    	
    	*bit = 0;
    	*cmp = 0;
    	
    	ret = _alu_end_bit( alu, num, &n );
    	
    	if ( ret != 0 )
    		return ret;
    	
    	ret = _alu_end_bit( alu, val, &v );
    	
    	if ( ret != 0 )
    		return ret;
    
    	N = alu->regv + num;
    	V = alu->regv + val;
    
    	ndiff = n.b - N->init.b;
    	vdiff = v.b - V->init.b;
    	
    	if ( ndiff > vdiff )
    	{
    		*bit = n.b;
    		*cmp = 1;
    		return 0;
    	}
    	
    	if ( ndiff < vdiff )
    	{
    		*bit = n.b;
    		*cmp = -1;
    		return 0;
    	}
    	
    	while ( ndiff )
    	{
    		ndiff--;
    		n = alu_bit_dec( n );
    		v = alu_bit_dec( v );
    		
    		a = (*(n.S) & n.B) ? 1 : 0;
    		b = (*(v.S) & v.B) ? 1 : 0;
    		
    		a -= b;
    		if ( a != 0 )
    		{
    			*bit = n.b;
    			*cmp = a;
    			return 0;
    		}
    	}
    	
    	return 0;
    }
    Last edited by awsdert; 07-29-2020 at 04:41 PM.

  7. #22
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,157
    Quote Originally Posted by awsdert
    part of the issue was no doubt a slight fault in my comparison function, fixed now (for reference it didn't account for init.b not being 0)
    Glad to hear that you found and fixed that.

    Going back to something I think I've mentioned to you before: have you considered automated unit testing? Right now you have what might be called an integration test, though it is more like a example usage that is used as a big integration test. To find these bugs, it looks like you're relying more on manual testing and debugging, which is okay, but it does make it harder for you to detect regressions and for people who might want to help you to see what might be wrong.

    If you had unit tests, then you could have greater confidence that the components that __alu_div depends on are working as expected, and hence the bug more likely lies with __alu_div itself. Furthermore, by looking at the failing tests, you might get a clue as to how it is failing and hence how to fix it.

    By the way, concerning naming the C standard has this to say:
    Quote Originally Posted by C11 7.1.3 Reserved identifiers
    — All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
    — All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
    This means that my example of _alu_vec_expand in post #7 is actually declaring with a reserved name, and likewise for your declarations of _alu_add, __alu_shl, __alu_div, etc.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #23
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Quote Originally Posted by laserlight View Post
    Glad to hear that you found and fixed that.

    Going back to something I think I've mentioned to you before: have you considered automated unit testing? Right now you have what might be called an integration test, though it is more like a example usage that is used as a big integration test. To find these bugs, it looks like you're relying more on manual testing and debugging, which is okay, but it does make it harder for you to detect regressions and for people who might want to help you to see what might be wrong.

    If you had unit tests, then you could have greater confidence that the components that __alu_div depends on are working as expected, and hence the bug more likely lies with __alu_div itself. Furthermore, by looking at the failing tests, you might get a clue as to how it is failing and hence how to fix it.

    By the way, concerning naming the C standard has this to say:

    This means that my example of _alu_vec_expand in post #7 is actually declaring with a reserved name, and likewise for your declarations of _alu_add, __alu_shl, __alu_div, etc.
    For automated tests I've never felt motivated to try them so for now that's a no, as for the naming convention the reason I add the underscore is that they are intended as internal functions, I'll write the wrappers later but for now I just want to make sure they work as intended

  9. #24
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Finally fixed it:
    Code:
    int __alu_div( alu_t *alu, int num, int val, int rem )
    {
    	int ret = _alu_check3( alu, num, val, rem ), cmp = 0;
    	alu_reg_t *N, *V, *R, TR, TV;
    	alu_bit_t n, v;
    	size_t bits = 0, bit;
    	
    	if ( ret != 0 )
    		return ret;
    		
    	N = alu->regv + num;
    	R = alu->regv + rem;
    	V = alu->regv + val;
    	
    	TR = *R;
    	TV = *V;
    	
    	memcpy( R->part, N->part, alu->buff.perN );
    	memset( N->part, 0, alu->buff.perN );
    
    	(void)_alu_end_bit( alu, rem, &(n) );
    	(void)_alu_end_bit( alu, val, &(v) );
    	
    	R->upto = alu_bit_inc(n); R->last = n;
    	V->upto = alu_bit_inc(v); V->last = v;
    	
    	for (
    		R->init = n; R->init.b > TR.init.b;
    		++bits, R->init = alu_bit_dec(R->init)
    	)
    	{
    		(void)_alu_cmp( alu, rem, val, &cmp, &bit );
    		
    		if ( cmp >= 0 )
    		{			
    			ret = _alu_sub( alu, rem, val );
    
    #if 0	
    			if ( ret == ENODATA )
    				break;
    #endif
    			
    			(void)__alu_shl( alu, num, bits );
    			*(N->init.S) |= N->init.B;
    			bits = 0;
    			ret = 0;
    		}
    	}
    	
    	if ( bits )
    	{
    		(void)_alu_cmp( alu, rem, val, &cmp, &bit );
    		(void)__alu_shl( alu, num, bits );
    		
    		if ( cmp >= 0 )
    		{
    			ret = _alu_sub( alu, rem, val );
    			*(N->init.S) |= N->init.B;
    		}
    	}
    	
    	*R = TR;
    	*V = TV;
    	
    	return ret;
    }
    And you'll notice that there is no check for value being 0, I just gotta test for the infinity loop, if it does then I'll re-enable that check for ENODATA

    Edit: There was no infinity loop however without the check the result was F recurring, enabling the check corrected the result
    Code:
    ...
    ./alu.AppImage
    test.c:163: main() 'Initiating ALU to 0...'
    test.c:171: main() 'Requesting register for number to modify...'
    test.c:180: main() 'Requesting register for value to modify by...'
    test.c:189: main() 'Comparing values...'
    test.c:50: compare() Expected 1, Got 1
    test.c:50: compare() Expected 0, Got 0
    test.c:50: compare() Expected -1, Got -1
    test.c:195: main() 'Adding values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected DEADC0DF, Got DEADC0DF, op = 'i'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected DEADC0E0, Got DEADC0E0, op = '+'
    test.c:199: main() 'Subtracting values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected DEADC0DD, Got DEADC0DD, op = 'd'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected DEADC0DC, Got DEADC0DC, op = '-'
    test.c:203: main() 'Shifting values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected 7AB70378, Got 7AB70378, op = '<'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected 37AB7037, Got 7AB70378, op = '>'
    test.c:207: main() 'Multiplying value...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected BD5B81BC, Got BD5B81BC, op = '*'
    test.c:210: main() 'Dividing values...'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected 6F56E06F, Got 6F56E06F, op = '/'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000000, _num = DEADC0DE, _val = 00000000
    test.c:153: modify() Expected 00000000, Got 00000000, op = '/'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    test.c:153: modify() Expected 00000000, Got 00000000, op = '%'
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000000, _num = DEADC0DE, _val = 00000000
    test.c:153: modify() Expected DEADC0DE, Got DEADC0DE, op = '%'
    Compilation finished successfully.
    Last edited by awsdert; 07-30-2020 at 05:32 AM.

  10. #25
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Don't have time to look into it right now but I noticed the right shift function is a few bits late
    Code:
    int __alu_shr( alu_t *alu, int num, size_t by )
    {
    	alu_reg_t *N;
    	alu_bit_t n, v, e;
    	int ret = _alu_check1( alu, num );
    	
    	if ( ret != 0 )
    	{
    		alu_error( ret );
    		return ret;
    	}
    	
    	N = alu->regv + num;
    	
    	n = N->init;
    	e = N->upto;
    	if ( by >= e.b ) by = e.b;
    	v = alu_bit_set_bit( N->part, n.b + by );
    	
    	while ( v.b < e.b )
    	{	
    		*(n.S) |= n.B;
    		*(n.S) ^= n.B;
    		
    		if ( *(v.S) & v.B )
    			*(n.S) |= n.B;
    			
    		v = alu_bit_inc( v );
    		n = alu_bit_inc( n );
    	}
    	
    	while ( n.b < e.b )
    	{
    		*(n.S) |= n.B;
    		*(n.S) ^= n.B;
    		
    		n = alu_bit_inc( n );
    	}
    	
    	return 0;
    }
    The bit results:
    Code:
    ...
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x56226ab606e0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 2, REG->last.s = 1, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x56226ab606e8, REG->last.S = 0x56226ab606e4, REG->init.S = 0x56226ab606e0
    0000000000000000000000000000000011011110101011011100000011011110
    test.c:154: modify() Expected 37AB7037, Got 7AB70378, op = '>'
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x56226ab606e0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 2, REG->last.s = 1, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x56226ab606e8, REG->last.S = 0x56226ab606e4, REG->init.S = 0x56226ab606e0
    0000000000000000000000000000001101111010101101110000001101111000
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x56226ab606e0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 2, REG->last.s = 1, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x56226ab606e8, REG->last.S = 0x56226ab606e4, REG->init.S = 0x56226ab606e0
    0000000000000000000000000000000000110111101010110111000000110111
    ...
    Maybe someone can spot the cause while I'm at work

  11. #26
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Quote Originally Posted by awsdert View Post
    Don't have time to look into it right now but I noticed the right shift function is a few bits late
    Code:
    int __alu_shr( alu_t *alu, int num, size_t by )
    {
    	alu_reg_t *N;
    	alu_bit_t n, v, e;
    	int ret = _alu_check1( alu, num );
    	
    	if ( ret != 0 )
    	{
    		alu_error( ret );
    		return ret;
    	}
    	
    	N = alu->regv + num;
    	
    	n = N->init;
    	e = N->upto;
    	if ( by >= e.b ) by = e.b;
    	v = alu_bit_set_bit( N->part, n.b + by );
    	
    	while ( v.b < e.b )
    	{	
    		*(n.S) |= n.B;
    		*(n.S) ^= n.B;
    		
    		if ( *(v.S) & v.B )
    			*(n.S) |= n.B;
    			
    		v = alu_bit_inc( v );
    		n = alu_bit_inc( n );
    	}
    	
    	while ( n.b < e.b )
    	{
    		*(n.S) |= n.B;
    		*(n.S) ^= n.B;
    		
    		n = alu_bit_inc( n );
    	}
    	
    	return 0;
    }
    The bit results:
    Code:
    ...
    test.c:85: modify() num = 4, val = 5, N = DEADC0DE, V = 00000002, _num = DEADC0DE, _val = 00000002
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x56226ab606e0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 2, REG->last.s = 1, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x56226ab606e8, REG->last.S = 0x56226ab606e4, REG->init.S = 0x56226ab606e0
    0000000000000000000000000000000011011110101011011100000011011110
    test.c:154: modify() Expected 37AB7037, Got 7AB70378, op = '>'
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x56226ab606e0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 2, REG->last.s = 1, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x56226ab606e8, REG->last.S = 0x56226ab606e4, REG->init.S = 0x56226ab606e0
    0000000000000000000000000000001101111010101101110000001101111000
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x56226ab606e0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 2, REG->last.s = 1, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x56226ab606e8, REG->last.S = 0x56226ab606e4, REG->init.S = 0x56226ab606e0
    0000000000000000000000000000000000110111101010110111000000110111
    ...
    Maybe someone can spot the cause while I'm at work
    Just got home and tried to look into the details of the register and bit count __alu_shr() receives only to find nothing printing, that lead me to notice I failed to change the macros that serve as _alu_shl() and _alu_shr() when I changed the final parameter of __alu_shift() (which does the job of converting a register into a size_t value if it's low enough otherwise -1 is given and default behaviour taken when bit count is higher than doable), with that fixed and a full rebuild I started seeing the correct result.

  12. #27
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,157
    Quote Originally Posted by awsdert
    For automated tests I've never felt motivated to try them so for now that's a no
    This is a very good opportunity to start though: you're writing a self-contained library such that you don't have to worry about things like mocking a database or a server. Plus it'll look good on your resume if you want to join a software engineering team rather than work solo or as a hobbyist (but arguably solo developers might benefit even more from automated unit testing since they don't have the benefit of peer review).

    Quote Originally Posted by awsdert
    as for the naming convention the reason I add the underscore is that they are intended as internal functions
    Yeah, I guessed as much, and did the same because I've been programming in Python lately, but the reserved name rules for Python are different from C. Unless you're going for a post-processing amalgamation approach like for SQLite (so you end up with one big source file regardless of how many you start with), you should declare your internal functions static: besides the benefit of avoiding name collision, it'll make it clear that they are internal regardless of naming convention.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #28
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Quote Originally Posted by laserlight View Post
    This is a very good opportunity to start though: you're writing a self-contained library such that you don't have to worry about things like mocking a database or a server. Plus it'll look good on your resume if you want to join a software engineering team rather than work solo or as a hobbyist (but arguably solo developers might benefit even more from automated unit testing since they don't have the benefit of peer review).


    Yeah, I guessed as much, and did the same because I've been programming in Python lately, but the reserved name rules for Python are different from C. Unless you're going for a post-processing amalgamation approach like for SQLite (so you end up with one big source file regardless of how many you start with), you should declare your internal functions static: besides the benefit of avoiding name collision, it'll make it clear that they are internal regardless of naming convention.
    Well aside from that making clear part what effect will marking them static have, as for the opportunity to learn, no arguments there, I just like to get details of failed tests which is easier to do manually, eventually I'll give "Check" a try which I found via google but that'll be more for identifying problem functions as apposed to printing details that can help find the root cause. Anyways I'll move onto the post I was gonna make (which I'll do separate from this one) when I came here.

  14. #29
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Started a rotate left and rotate right function, ran into a problem (just as I was going to start typing this post I thought of a possible cause of the mismatch so tried it out, one did match but other didn't, did enlighten me to a hidden problem elsewhere though so going to post the output then a separate post for each function to make quoting the relevant part easier:
    Code:
    ...
    ./alu.AppImage
    test.c:200: main() 'Initiating ALU to 0...'
    test.c:203: main() 'Pre-allocating 16 ALU registers...'
    test.c:206: main() 'Requesting register for number to modify...'
    test.c:215: main() 'Requesting register for value to modify by...'
    test.c:224: main() 'Comparing values...'
    test.c:56: compare() Expected 1, Got 1
    test.c:56: compare() Expected 0, Got 0
    test.c:56: compare() Expected -1, Got -1
    test.c:230: main() 'Adding values...'
    test.c:179: modify() 00000000DEADC0DE++, Expected 00000000DEADC0DF, Got 00000000DEADC0DF, op = 'i'
    test.c:179: modify() 00000000DEADC0DE + 0000000000000002, Expected 00000000DEADC0E0, Got 00000000DEADC0E0, op = '+'
    test.c:179: modify() 00000000DEADC0DE + 0000000000000000, Expected 00000000DEADC0DE, Got 00000000DEADC0DE, op = '+'
    test.c:235: main() 'Subtracting values...'
    test.c:179: modify() 00000000DEADC0DE--, Expected 00000000DEADC0DD, Got 00000000DEADC0DD, op = 'd'
    test.c:179: modify() 00000000DEADC0DE - 0000000000000002, Expected 00000000DEADC0DC, Got 00000000DEADC0DC, op = '-'
    test.c:179: modify() 00000000DEADC0DE - 0000000000000000, Expected 00000000DEADC0DE, Got 00000000DEADC0DE, op = '-'
    test.c:240: main() 'Shifting values...'
    test.c:179: modify() 00000000DEADC0DE << 0000000000000002, Expected 000000037AB70378, Got 7AB70379FFFFFFFC, op = '<'
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    0111101010110111000000110111100111111111111111111111111111111100
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    0000000000000000000000000000001101111010101101110000001101111000
    test.c:179: modify() 00000000DEADC0DE >> 0000000000000002, Expected 0000000037AB7037, Got 0000000037AB7037, op = '>'
    test.c:244: main() 'Multiplying values...'
    test.c:179: modify() 00000000DEADC0DE * 0000000000000002, Expected 00000001BD5B81BC, Got BD5B81BCFFFFFFFE, op = '*'
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    1011110101011011100000011011110011111111111111111111111111111110
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    0000000000000000000000000000000110111101010110111000000110111100
    test.c:179: modify() 00000000DEADC0DE * 0000000000000000, Expected 0000000000000000, Got 0000000000000000, op = '*'
    test.c:248: main() 'Dividing values...'
    test.c:179: modify() 00000000DEADC0DE / 0000000000000002, Expected 000000006F56E06F, Got FFFFFFFEFFFFFFFF, op = '/'
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    1111111111111111111111111111111011111111111111111111111111111111
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    0000000000000000000000000000000001101111010101101110000001101111
    test.c:179: modify() 00000000DEADC0DE / 0000000000000000, Expected 0000000000000000, Got 0000000000000000, op = '/'
    test.c:179: modify() 00000000DEADC0DE % 0000000000000002, Expected 0000000000000000, Got 0000000000000000, op = '%'
    test.c:179: modify() 00000000DEADC0DE % 0000000000000000, Expected 00000000DEADC0DE, Got 00000000DEADC0DE, op = '%'
    test.c:254: main() 'Rotating values...'
    test.c:179: modify() 00000000DEADC0DE <<< 0000000000000002, Expected 000000037AB70378, Got 7AB7037800000000, op = 'l'
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    0111101010110111000000110111100000000000000000000000000000000000
    alu_main.c:86: alu_pri_reg() reg = 4, REG->part = 0x55d42e9f42c0
    alu_main.c:88: alu_pri_reg() REG->upto.b = 64, REG->last.b = 63, REG->init.b = 0
    alu_main.c:93: alu_pri_reg() REG->upto.s = 1, REG->last.s = 0, REG->init.s = 0
    alu_main.c:98: alu_pri_reg() REG->upto.S = 0x55d42e9f42c8, REG->last.S = 0x55d42e9f42c0, REG->init.S = 0x55d42e9f42c0
    0000000000000000000000000000001101111010101101110000001101111000
    test.c:179: modify() 00000000DEADC0DE >>> 0000000000000002, Expected 8000000037AB7037, Got 8000000037AB7037, op = 'r'
    Compilation finished successfully.

  15. #30
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,138
    Left shift:
    Code:
    int __alu_shl( alu_t *alu, int num, size_t by )
    {
    	alu_reg_t *N;
    	alu_bit_t n = {0}, v;
    	int ret = _alu_check1( alu, num );
    	
    	if ( ret != 0 )
    	{
    		alu_error( ret );
    		return ret;
    	}
    	
    	N = alu->regv + num;
    	
    	n = N->upto;
    	if ( by >= n.b ) by = n.b;
    	v = alu_bit_set_bit( N->part, n.b - by );
    	
    	while ( v.b > N->init.b )
    	{
    		v = alu_bit_dec( v );
    		n = alu_bit_dec( n );
    		
    		*(n.S) |= n.B;
    		*(n.S) ^= n.B;
    		
    		if ( *(v.S) & v.B )
    			*(n.S) |= n.B;
    	}
    	
    	while ( n.b > N->init.b )
    	{
    		n = alu_bit_dec( n );
    		
    		*(n.S) |= n.B;
    		*(n.S) ^= n.B;
    	}
    	
    	return 0;
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Left and right shift operators
    By Eclipse07 in forum C Programming
    Replies: 4
    Last Post: 12-15-2019, 08:28 PM
  2. Bignum math: right shift
    By awsdert in forum C Programming
    Replies: 1
    Last Post: 11-21-2019, 05:13 AM
  3. c bit shift left and right
    By ssm in forum C Programming
    Replies: 8
    Last Post: 03-01-2016, 02:09 PM
  4. Shift Left, Shift Right Question
    By congi in forum C Programming
    Replies: 1
    Last Post: 01-28-2015, 10:45 AM
  5. Left Shift
    By vb.bajpai in forum C Programming
    Replies: 4
    Last Post: 06-17-2007, 11:15 AM

Tags for this Thread